《Minecraft指令手册》 开群啦 群号:,名称:minecraft指令交流群。 如何给弓射出的箭加上光轨效果? (不推荐阅读此教程) 有一位书友在第四十一章下面提了一个问题:如何用指令来设置弓箭的光轨效果。 首先,像这样的效果,而且是常用的,就得使用命令方块(见第二章)。命令方块的配置得是: 保持开启或红石控制 循环 无条件 并且,如果真的要做起来的话,还得用\/tickingarea加上一个常加载区块(见第三十二章),或把这个命令方块放到常加载区块那里。 然后就得进入指令环节了。 既然是光轨效果,也就是特效,那么就得用到\/particle(见第三十九章)指令。 java版的\/particle可以直接指定目标,所以不需要再套个\/execute(见第三十三章)。 那么目标选择器(见第四章、二十五章和二十六章)由于不是指定玩家,就得使用@e加上type。箭的id是arrow,所以目标选择器就是: @e [type =arrow] 那么套入公式,就得到: \/particle 颗粒id~~~ 0 0 0 0 0 normal @e [type =arrow] 其中,每次我们只需要一个粒子,并且也不需要它运动,并且生成的位置必须正正好好在箭那里,显示模式的话也不需要搞太复杂,正常就行了(当然你要不正常也可以)。 最后也就是选择颗粒了。minecraft有很多种颗粒,但是我们必须要选择最适合的几种。 但是这个我们最后讨论。再来看看基岩版怎么弄。 基岩版就需要\/execute了。 所以,将\/particle套入\/execute,并加上刚刚我们得出的数据,就得出: \/execute @e [type =arrow]~~~ particle 颗粒id~~~ 所以,最后来研究研究颗粒选啥。 这里给出一个网址,方便大家查id: h t t p s :\/\/ m i n e c r a f t - z h . g a m e p e d i a . c o m \/% e 9 % a 2 % 9 7 % e 7 % b 2 % 9 2 这是minecraft wiki的网址,比较官方的,内容比较全(但有些仍然不全),大家放心去看。 作者这边选择了比较适合的粒子效果: end_rod(基岩版为endrod)——末地烛的效果,为白色。 falling_dust(基岩版为fallingdust)——沙子浮空底下的粒子效果,为淡黄色。 va——熔岩的粒子效果,为橙色。 smoke——烟雾,为灰色 你们把id套上去即可。如果觉得不行还可以去翻一翻,也可以使用dust来自定义。 如果还有疑问,可以在章尾留言,作者有时间的话会去解答。 如何制作一个起床战争资源点?(双版本通用版) (作者建议未看到第七十七章的读者离开此教程) (该教程可能会有更好地替代方法,具体见第九十三章的内容) 我相信有很多读者都有这个疑问。 那么今天我们就来解答这个疑问:如何制作一个起床战争资源点? 首先,我们先设想几个方案。 估计绝大多数人一开始都会想到:\/summon。 确实,\/summon是生成实体,掉落物也是实体。 所以我们先从\/summon这个角度出发。 掉落物的id是item,按照常理来说,使用\/summon的生成方式是: \/summon item ~~~ 但问题来了,怎么指定物品呢? 这个时候,就要用到我们的nbt了。 既然提到了nbt,那么基岩版玩家就可以跳过这段了。 但是由于这段nbt作者都还没讲到,所以这个方法就先告一段落。 基岩版玩家现在可以回来了(明明什么都没讲啊?)。 那么\/summon这个方法不用的话,那该怎么办? 想一想?还有什么可以产生自定义掉落物? 是不是想到了? 没错,就是\/fill和\/setblock的destroy模式。 然后再配上一个箱子,放入物品,重复克隆,再打碎,不就很棒吗? 而且,这个基岩版也可以用! 那么首先,我们需要准备一个箱子。 箱子里放入一个你要产生的资源(比如一颗砖块[铜锭]) 然后记住这个箱子的坐标。 在旁边放上一个重复循环的命令方块,里面写上: \/clone 箱子的xyz 箱子的xyz 资源点的xyz 然后当这个重复循环命令方块执行成功时,激活下一个命令方块(链,有条件的,保持开启):\/setblock 资源点的xyz air 0 destroy [java1.12版本及以下、基岩版可用] (\/setblock 资源点的xyz air destroy [java1.12版本以上可用]) 这样子,你就成功制作了一个每秒钟可以产出20铜锭的资源点。 是不是有点快了? 那就加一个计时装置。 普通的你可以照第九十一章的做,但这样子应用到起床战争这种场景,很容易被摧毁。 怎么办呢? 制作一个“计分板计时装置”。 首先,新建一个命令链(只需要一个重复循环命令方块)。 然后在聊天栏使用: \/scoreboard objectives add 计时 dummy 这样子就有一个计时器了。 然后给计时器添加第一个项目(命令方块里写): \/scoreboard yers add 铜锭资源点`计时 1 (注:“`”为分割符号,因为起点的特殊性,会把空格屏蔽掉。在写的时候请删掉这个符号) 这样子运行命令方块,你就成功开始了第一个计时项目。 只不过单位要搞清楚,这个计时单位为“游戏刻”。 换算成秒还要除以20,别搞错了。 然后我们再设置清零装置——在clone命令方块前面摆上一个循环命令方块,同时clone要改成链、有条件的、保持开启。 命令方块里写上: \/scoreboard yers set @e[scores:{计时=20..}]计时 0 当“铜锭资源点“的计时达到20游戏刻,也就是1秒钟时,清零,并激活clone,再激活setblock。 酱紫,你的铜锭资源点的速度就下降到了1s\/个。 上面的名字可以依照个人需求任意改,而这个循环速度也可以自己改(就是那个计时=20..那个)。 但接下来又出现了一个新的问题:这个箱子打碎的粒子会露馅啊! 这简单,我们可以将箱子复制到另一个地方,比如命令方块的头上。 然后再打碎。 最后添加一个命令方块在\/setblock后面(链、有条件的、保持开启):\/tp @e[name =钻石,type =item,c =1]资源点xyz 当然保险起见还可以再加一个r以及xyz参数,防止bug。 这样子你就成功获得了一个足以媲美hypixel的资源点了! ok这期教程就到这里了,认为不错的话投个票点个收藏,作者现在已经开学了,但信亏这周没考试(verygood),但下周的话就..... 怎样简单的开一个java服务器? 上 (该教程废话很多,且仅仅适用于原版minecraft java服务器,不适用于mod服和插件服) 其实很简单,首先,你需要一个java的服务器端,你可以在正版java我的世界下载或者是在mcbbs下载。注意,服务器端一定要下对应你想开的minecraftjava版本,比如开1.12.2服务器就需要用到对应的1.12.2服务器的jar服务端包。 mcbbs的下载可以在百度上搜一个固定格式: minecraft 1.x.x 纯净客户端文件&官方服务端下载 然后打开最接近的mcbbs帖子,大概率是过期资源板块。 点进去,找到“1.xx.x正式版官方服务端”,点击下载链接就可以了。 什么?等级不够无法访问板块? 很简单,百度上基本每个链接右下角都有一个“百度快照”,点进去,你就可以浏览了,不受等级不够的束缚。 下好后你就需要选择一个文件夹,最好是干干净净的,把这个jar服务器端包放进去。 然后你就需要确认你这个jar包名字(注意要打开后缀)是否是: server.jar 不然下面会出很严重的大问题的。 第三步你需要创建一个txt文件,在里面写上: @echo off color 0 title minecraft server java -xms2g -xmx2g -jar server.jar pause 其中,xms后面的2g是服务器最大内存,xmx后面的2g是服务器最小内存,你也可以根据情况以及电脑配置而更改。(所以电脑最少也要4g内存) title是该窗口的标题,你也可以自由更改,但最好不要使用中文。 然后保存关闭,并把文件后缀名改成bat。 注意,这个文件是一个非常重要的文件,以后开启服务器就需要双击这个文件,所以可以把文件名改改。 双击运行该文件,此时会跳出终端界面,依次显示(括号里为翻译): starting minecraft server version 1.xx.x(启动我的世界服务器1.xx.x,x会根据你实际使用的服务端我的世界版本而改变) loading properties(加载配置文件) server.properties does not exist(没有找到server.properties文件) generating new properties file(创建新的properties配置文件) failed to load e.txt(加载用户协议文件失败) you need to agree to the e in order to run the server.go to e.txt for more info.(你需要同意用户协议来启动这个服务器,去e.txt获取更多信息) stopping server(正在停止服务器) stopping server(正在停止服务器) [关闭窗口] 窗口关闭后,你的服务器文件夹会出现下列几个东西: logs文件夹——这是服务器运行的信息,相当于服务器日志 e.txt——在终端里说过了,这是mojang的用户协议 server.properties——在终端里说过了,这是服务器的配置文件,也就是设置文件。 终端里说我们需要同意用户协议(e),所以我们第四步需要打开e.txt。 打开后,会有两行注释和一行参数,即: #by changing the setting below to true you are indicating your agreement to our e ( #thu xxx xx xx:xx:xx xxx xxxx e=false 注释翻译成中文就是: #将下列的设置改为true,表示您同意我们的用户协议( #时间xxxx年xx月xx日星期x,xx:xx:xx 第一行的网址是用户协议的网址,可以去看一下。如果你打算要拿服务器来进行商业行为,那么最好还是看一下。 第二行的时间就是你第一次启动生成这些文件的时间。 好,现在我们把这个e改成true来同意mojang的用户协议(虽然根本就没看),然后保存并退出。 接下来打开配置文件,此时你就会发现配置文件空空如也。 这是为什么? 因为你还没有导入存档啊! 创建一个纯净1.12.2的存档,然后把其复制到服务器的根目录,并把文件夹名改成world(世界)。 接着再次双击我们最初创建的bat文件,然后就又跳出终端。 这次终端显示了: starting minecraft server version 1.xx.x(启动我的世界服务器1.xx.x) loading properties(加载配置文件) default game type:survival(默认游戏类型:生存) generating keypair(生成密钥) starting minecraft server on *:(启动minecraft服务器于端口) using default channel type(使用默认通道类型) 接着跳出了一个一闪而过的白色窗口,这个窗口就是minecraft server后台。 左上角是stats,显示着服务器内存使用(memory use)和avg tick(平均刻度) 左下角是yers,显示着当前在线的玩家。 右边是log and chat,显示着服务器日志和服务器聊天内容,下面有一栏输入框,用于执行指令。注意,这里的指令开头不需要带\/。这里的内容和终端显示内容互通。 接着窗口关闭。 这时候我们就可以用记事本打开server.properties配置服务器了,这里介绍介绍里面的参数: spawn-protection——出生点保护,可以保护出生点周围的土地,也就是变相保护主城,防止熊孩子破坏。默认是以出生点为中心的32x32x256的这个范围,也就是16(这个数值是指出生点保护半径,也就是保护范围正方形边长的一半) max-tick-time——最长待机时间,默认刻 max-yers——最大玩家数量,默认20,不想服务器负担太大也可以调小。 allowher——开关下界,默认开启(true) broadcast-console-to-ops——广播控制台信息到op聊天栏,默认开启(true) enable-query——是否允许使用gamespy4协议的服务器监听器,获取服务器信息,默认关闭。 enable-rcon——是否远程访问服务器控制台,默认关闭 yer-idle-timeout——这个作者不知道,好像是管理挂机玩家的。 resource-pack——这就是服务器资源包了,可以在这里配置服务器要用什么资源包。 online-mode——正版验证,默认true,关闭才可以让非正版玩家进入服务器,强烈建议关闭 gamemode——默认游戏模式,就是其他玩家第一次进服的模式,数值是模式数字id,也可以英文。 difficulty——默认游戏难度,进入游戏后是不能直接在控制里改的。数值是游戏难度数字id,也可以英文。 hardcore——这应该指极限模式,最好关着 spawn-animals——生成动物,默认开着(true),不想动物也可以关掉。 spawn-monsters——生成怪物,默认开启(true),不要怪物也可以关掉 op-permission-level——op默认等级,具体介绍可以前往第六章玩家权限查看。 function-permission-level——设定函数的默认权限等级,默认为2。 server-ip——服务器ip,最好不要动,留空 pvp——玩家之间的战斗,默认开(true)。 server-port——服务器端口,千万不要动!!!让它保持 allow-flight——允许飞行,默认关闭,开着的话生存玩家也可以享受飞翔的快乐了。创造模式不受影响。如果关闭,当玩家使用mod或开挂时,悬空超过5秒就会被踢出服务器。 prevent-proxy-connections——阻止代理连接,最好还是保持关闭,不然到时候内网穿透估计会出bug force-gamemode——强制游戏模式,默认关闭,开起来的话填模式英文id,作用就是玩家每次进入都会以默认游戏模式进入,而不是上次退出游戏的模式。 spawn-npcs——生成npc,开起来才会生成村民等npc generate-structures——生成结构,默认开启(true),关了就不会生成建筑了。地牢不受影响。 motd——这是服务器下面的一栏介绍,只能填英文,中文会报错,且最大最好不要超过59个字符,超过很有可能服务器会报错。 resource-pack-sha1——好像跟资源包有关系 enable-mand-block——开启命令方块,默认false,最好true开起来。 max-world-size——世界大小,默认是,即玩家可活动范围是从x=-,z=-到x=,z=这之间的正方形范围,其边缘是世界边界,出去就会受到伤害,在单人游戏也是这样,你可以通过tp到上面这两个夹角来看到世界边界。 level-name——世界名称,默认world,这就是为什么要你最开始把世界名改成world,配置好后世界名就可以改了(最好不要改中文),改完这边再改一下就行了。 view-distance——玩家视距,这可以限定玩家的视距,来让服务器减少负担。默认10(单位:区块) white-list——服务器白名单,默认关闭,你可以到第五十一章了解一下。 max-build-height——世界建筑高度,默认256,你也可以改得更低,这个可以适用于起床战争这类pvp,防止敌人搭高高。 level-seed——种子,如果要写需要把世界移除掉,然后重新启动bat开启服务器。 好了,设定完了,你现在可以保存关闭配置,接着再双击bat文件运行服务器。 这时候是最后一次配置,当窗口没有新消息的时候就关闭窗口,然后你就会发现服务器又多了一些新的文件: banned-ips.json——ip黑名单全存在这 banned-yers.json——玩家名黑名单全存在这 ops.json——服务器op信息全存在这 usercache.json——玩家缓存都在这 whitelist.json——服务器白名单都在这 这些文件你可以用记事本打开看看车,然后你就可以再次运行服务器了(双击bat) 好了,现在服务器已经成功开启了,你可以看到终端上出现了: starting minecraft server version 1.xx.x(启动我的世界服务器1.xx.x) loading properties(加载配置文件) default game type:xxx(默认游戏类型:xxx) generating keypair(生成密钥) starting minecraft server on *:(启动minecraft服务器于端口) using default channel type(使用默认通道类型) **** server is running in offline\/insecure mode!(服务器正在脱机\/不安全模式下运行!) the server will make no attempt to authenticate usernames.beware.(服务器不会尝试进行身份验证用户名。小心。)——这只会在你关闭online-mode正版验证情况下出现。 while this makes the game possible to y without inte ess,it also opens up the ability for hackers to connect with any username they choose.(虽然这使得游戏可以在没有互联网接入的情况下玩,但它也为黑客提供了使用他们选择任何用户名进行连接的能力。)——这也只会在你关闭online-mode正版验证情况下出现。 to change this set “online-mode“ to “true“ in the server.properties file.(可以在server.properties配置文件里更改online-mode为true)——这还是只会在你关闭online-mode正版验证情况下出现。 preparing level “world“(准备生成世界) loaded 488 advancements(载入488个进度) preparing start region for level 0(正在为等级0区块准备开始区域)——这边应该指的是区块加载等级,和第一百二十章讲的区块卸载差不多,只不过反过来了。 这时候会停顿一下,然后: done (0.978s)!for help.type“help“or“?“——完成!你可以输入help或?获取帮助。 这时候服务器就开启了,你可以在java服务器后台输入stop关闭服务器(其实就相当于在服务器输入\/stop指令,这条指令作用就是关闭服务器) 当然直接关掉界面也可以,只不过可能会导致服务器回档。 这时候,你就已经可以进入服务器了,只不过只能在本地进入,由于服务器端口是,你就可以在我的世界客户端多人游戏中“添加服务器”然后输入: 127.0.0.1: 现在来进入服务器,其中127.0.0.1是本地电脑的默认ip,就是在本地电脑ip开的端口。 但是你肯定会发现,进去之后你竟然没有权限! 这很正常,但是我们该如何获得权限? 很简单,后台也是可以执行指令的,所以我们可以在服务器后台,也就是java那个界面,输入:op 你的游戏id 然后游戏里就会出现一条消息,接着你就被设为管理员了。 你可以在ops.json里看到有op权限人的uuid、name、level(权限等级)、和bypassesyerlimit。 其中,level权限等级上面提过了,如果管理熊了你可以在后台把其等级降低或者是直接把其这一段完全删掉,这样子也可以撤销其权限。 (恩,把等级降低那么其就有名无实了[奸笑]) 而bypassesyerlimit默认是false,这个作用就是如果为true,那么op就可以在服务器满人的时候强行进入服务器。 好了,现在你已经知道如何简单的开一个java服务器,那么下一章我们将会讲到如何把服务器映射到公网供其他玩家自由进入服务器(免费的)。 本书第一次大修进程表 这个章节是『本书第一次大修』的进程表,我会在这里粗略列出各章节的修改情况。 ———图例 ○······无修改计划,可能不会修改 □······有修改计划,但还未修改 ◇······有被小幅度的修改 ☆······有被大幅度的修改,但未重写 ★······有被重写 ?······章节主要内容被改变 ?······章节名称被改变 ?······卷名被改变 ?······新增章节 ?······章节被删除 ⊙······将会被再次修改 ———章节列表 --新手入门 序言★ 第一章作弊与输入指令☆? 第二章命令方块☆ 第三章§☆? 第四章目标选择器★ 第五章坐标★ 第六章玩家类别与权限等级☆? 第七章指令的格式与指令执行的三要素★? mc新手要学习的基础—1—红石信号□ mc新手要学习的基础—2—minecraft版本的区分◇? --常用基础指令 第八章\/give的用法☆ 第九章 tp-传送指令☆ 第十章 kill-熊孩子最喜欢的指令◇ 第十一章 gamemode-更改游戏模式◇ 第十二章 gamerule-自定游戏规则◇ 第十三章 clear-清除物品的指令☆ 第十四章 fill-填充指令◇ 第十五章发送消息☆? 第十六章 title-屏幕标题☆? 第十七章 java版json文本初识☆? 第十八章基岩版特殊符号★ 第十九章 time-改变时间◇ 第二十章 weather-控制天气◇ 第二十一章一些短小但不容忽视的指令☆ 第二十二章 summon-生成实体☆ 第二十三章 setblock-放置方块◇ 第二十四章 xp-控制经验值☆ --进入中等级别? 第二十五章更加精确的目标选择器上☆ 第二十六章更加精确的目标选择器下☆ 第二十七章游戏刻☆? 第二十八章区块与区段☆? 第二十九章更深入地了解指令参数★?? 第三十章方块☆ 第三十一章实体☆ --又是一些指令? 第三十二章 tickingarea-基岩版控制常加载区块★? 第三十三章 execute-这年头,猪都会说话了★ 第三十四章 setworldspawn、spawnpoint-出生点★ 第三十五章 spreadyers-随机传送★ 第三十六章 testfor -探测上☆ 第三十七章 testforblock、testforblocks-探测下★ 第三十八章 receitem-头上顶着一个tnt☆ 第三十九章 particle-在mc里做特效★ --记分版\/计分板(scoreboard)? 第四十章记分板是什么鬼★? 第四十一章 objectives——管理一个计分项★ 第四十二章 yers——管理变量(分数)★? 第四十三章 yers——记分板商店★? 第四十四章在minecraft用指令算1+1=?★ 新年好! 第四十五章变量的几种常用用途(破百收藏纪念)◇ 第四十六章 team——管理队伍和成员★? 第四十七章 team——队伍的颜色和规则★? 第四十八章 tag-标签★?? 第四十九章目标选择器中的记分板★? --服务器中的指令? 第五十章多人游戏指令★?? 第五十一章 whitelist-白名单★ 第五十二章\/kick和黑名单系统★?? 第五十三章剩下的一些指令★?? 第五十四章初识nbt★?? --更多的指令 第五十五章 effect-牛顿哭了★ 第五十六章 clone-拷贝方块★? 第五十七章 enchant-简单的附魔★ 第五十八章使用nbt来自定义附魔★? 第五十九章更深入地了解坐标★ 第六十章基岩版的json文本(破200收藏纪念)★ 第六十一章\/stats与指令的输出结果★?? 第六十二章命令方块矿车★ 第六十三章游戏声音★? 第六十四章 tp和teleport-深入地了解传送指令★? 第六十四章番外我在这里!? 本书第一次大修新增章1矿词与标签? 第六十五章 worldborder-mc是一款吃鸡游戏★ 第六十六章指令大杂烩★?? 第六十七章更高级的locate★? --更高级的execute? 第六十八章新版execute的变化★?? 第六十九章修饰子命令上三要素与修饰子命令★?? 第七十章修饰子命令下剩下的5个修饰子命令★?? 第七十一章条件子命令★?? 第七十二章存储子命令★?? 第七十三章基岩版的新版execute★?? 第七十四章探究:execute的运行流程★?? 第七十五章局部坐标与执行朝向★?? 第七十六章 camerashake-如何让一个玩家鬼畜★?? 第七十七章 damage-造成伤害★?? --?是一些指令? 第七十八章 event-生物事件★?? 第七十九章结构方块上★? 第八十章结构方块下★ 第八十一章 structure-指令与结构方块★?? 第八十二章 fog-迷雾★?? 第八十三章 bossbar-自定义boss栏上★ 第八十四章 bossbar-自定义boss栏下★ 第八十五章 item-更高级的receitem★?? 第八十六章 music-音乐★?? 第八十七章拼图方块★?? 第八十八章 ce-如何生成一个村庄★?? 关于最近为什么没更的问题? 第八十九章 ride-骑乘★?? 第九十章命名空间id★? --真正进入中阶? 第九十一章红石比较器★?? 第九十二章简单的红石脉冲★?? 第九十三章逻辑门上★? 第九十四章逻辑门下★? 第九十五章初识逻辑组★?? minecraft2020愚人节更新介绍(实际上是让你看mc wiki)? 第九十六章如何正确使用一个盔甲架◇ 第九十六章番外如何获得一个拥有手臂的盔甲架◇ 第九十六章番外的番外看,这个盔甲架高兴极了☆ 要想成为一个指令大佬,首先你得拥有一个指令生成器? 第九十七章 forceload-java版控制常加载区块★? 第九十八章触发器-简单的注册\/登录系统上★?? 第九十九章初识模块-简单的注册\/登录系统下★?? --nbt时代 第一百章开启nbt时代(来,开杯香槟酒庆祝一下,100章了)★?? 第一百零一章简单了解数组★?? 第一百零二章物品组件★? 第一百零三章《关于工具耐久的这档事》★ 第一百零四章物品的显示属性★ 基岩版玩家的级锋利的苹果☆ 第一百零五章属性修饰符上-哪个mc玩家不想拥有一套神装呢?★? 第一百零六章属性修饰符下-最终倍乘和\/attribute指令★? 第一百零七章如何获取你在minecraft中的头★ 有一个坏消息? 祝贺minecraft11周年生日快乐!◇ 第一百零八章掉落物的nbt 上-物品通用标签★? 第一百零九章掉落物的nbt 下☆ 第一百一十章 uuid☆ 请假条? 第一百一十一章网易的特性:实体mod◇ 第一百一十二章实体的通用标签上★ 第一百一十三章实体的通用标签下☆ 又是一张请假条? --中场休息 第一百一十四章死亡的玩家到底是不是个实体?○ 第一百一十五章 websocket在minecraft里的用处□ 第一百一十六章 advancement-让人一夜回到解放前的指令○ 第一百一十七章控制成就系统的指令○ 第一百一十八章 ability-怎样禁言一个人○ 第一百一十九章称号系统□ 第一百二十章区块加载器○ --java版的json 第一百二十一章 json的格式□ 第一百二十二章 json的内容上□ 第一百二十三章 json的内容下□ 第一百二十四章 json的格式元素□ 第一百二十五章玩家与json的交互事件上□ 第一百二十六章玩家与json的交互事件下□ 第一百二十七章 json剩下の一些东西□ 第一百二十八章营销号写指令教程□ --实体与nbt 上 第一百二十九章深入地了解一下实体○ 第一百三十章 mc生物学○ 第一百三十一章生物的共通nbt-1○ 第一百三十二章生物的共通nbt-2○ 第一百三十三章生物的共通nbt-3○ 第一百三十四章生物的共通nbt-4○ 第一百三十五章真正深入了解nbt-1○ 第一百三十六章真正深入了解nbt-2○ 第一百三十七章真正深入了解nbt-3○ 第一百三十八章真正深入了解nbt-4○ 第一百三十九章真正深入了解nbt-5○ 第一百四十章真正深入了解nbt-6○ 第一百四十一章牛顿心中的minecraft:下落的方块○ 第一百四十二章矿车共通标签○ 第一百四十三章\/entitydata-修改实体的nbt○ 第一百四十四章弹射物共通标签○ 第一百四十五章箭共通标签○ 第一百四十六章火球○ 第一百四十七章可繁殖的生物共通标签○ --调戏minecraft指南 第一百四十八章如何看懂调试界面1○ 第一百四十九章如何看懂调试界面2○ 第一百五十章如何看懂调试界面3○ 第一百五十一章如何看懂调试界面4○ 第一百五十二章调试棒和其他的一些关于调试的东西○ --村民与npc 第一百五十三章详细了解村庄更新之前的村民○ 第一百五十四章村庄与掠夺更新前的自定义交易○ 虎年快乐!○ 第一百五十五章村庄与掠夺更新后的村民○ 第一百五十六章村庄与掠夺更新后的自定义交易○ ———温馨提示 对于★有被重写且不计划再次修改的(没有⊙),推荐重新阅读 对于?章节主要内容改变的和?新增的章节,强烈推荐重新阅读 对于带⊙和□将要修改的,不推荐重新阅读 对于☆大幅度修改和◇小幅度修改的,不太推荐重新阅读 索引章 (更新时间:2022.8.15) ——指令 \/?→第二十一章 \/ability →第一百一十八章 \/achievement →第一百一十七章 \/advancement →第一百一十六章 \/alwaysday →第六十六章 \/attribute →第一百零六章 \/ban →第五十二章 \/banip →\/ban-ip \/ban-ip →第五十二章 \/banlist →第五十二章 \/blockdata →暂未讲到 \/bossbar →第八十三章、第八十四章 \/broadcast →\/say \/camerashake →第七十六章 \/changesetting →不会讲 \/chunk →\/forceload \/clear →第十三章 \/clearspawnpoint →第三十四章 \/clone →第五十六章 \/connect →第一百一十五章(第八十五章原有讲到,后删除) \/damage →第七十七章 \/data →暂未讲到 \/datapack →暂未讲到 \/daylock →第六十六章 \/debug →第一百五十二章 \/defaultgamemode →第六十六章 \/deop →第五十三章 \/detect →\/execute \/dialogue →暂未讲到 \/difficulty →第六十六章 \/effect →第五十五章 \/enchant →第五十七章 \/entitydata →第一百四十三章 \/event →第七十八章 \/execute →第八卷、第三十三章 \/executeasself →\/execute \/experience →第二十四章 \/fill →第十四章 \/fog →第八十二章 \/forceload →第九十七章 \/function →暂未讲到 \/gamemode →第十一章 \/gamerule →第十二章 \/gametest →暂未讲到 \/getspawnpoint →第三十四章 \/give →第八章 \/help →第二十一章 \/immutableworld →暂未讲到 \/item →第八十五章 \/jfr →暂未讲到 \/kick →第五十二章 \/kill →第十章 \/list →第五十三章 \/listd →第五十三章 \/locatebiome →第六十七章 \/locate →第二十一章、第六十七章 \/loot →暂未讲到(以前有讲,后被移除) \/me →第十五章 \/mobevent →第六十六章 \/msg →第十五章 \/music →第八十六章 \/op →第五十三章 \/ops →不会讲 \/pardon →第五十二章 \/pardon-ip →第五十二章 \/particle →第三十九章 \/perf →第一百五十二章 \/permission →不会讲 \/ce →第八十八章 \/cefeature →第八十八章 \/yanimation →暂未讲到 \/ysound →第六十三章 \/position →\/gamerule \/publish →第六十六章 \/recipe →第六十六章 \/reload →暂未讲到 \/remove →不会讲 \/receitem →第三十八章 \/resupply →\/event \/ride →第八十九章 \/save →第五十三章 \/save-all →第五十三章 \/save-off →第五十三章 \/save-on →第五十三章 \/say →第十五章 \/schedule →暂未讲到 \/scoreboard →第五卷 \/seed →第二十一章 \/setblock →第二十三章 \/setidletimeout →第五十三章 \/setmaxyers →第六十六章 \/setworldspawn →第三十四章 \/spawnpoint →第三十四章 \/spectate →第六十六章 \/spreadyers →第三十五章 \/stats →第六十一章 \/stop →第五十三章 \/stopsound →第六十三章 \/structure →第八十一章 \/summon →第二十二章 \/tag →第四十八章 \/team →第四十六章 \/teammsg →第六十六章 \/teleport →第六十四章 \/tell →第十五章 \/tellraw →第十五章、第十七章 \/testfor →第三十六章 \/testforblock →第三十七章 \/testforblocks →第三十七章 \/tickingarea →第三十二章 \/time →第十九章 \/title →第十六章 \/titleraw →第十五章、第十六章 \/tm →第六十六章 \/toggledownfall →第二十章 \/tp →第九章、第六十四章 \/trigger →第九十八章 \/unban →\/pardon \/volumearea →暂未讲到 \/w →第十五章 \/wb →暂未讲到 \/weather →第二十章 \/whitelist →第五十一章 \/worldborder →第六十五章 \/worldbuilder →暂未讲到 \/wsserver →第一百一十五章(第八十五章原有讲到,后删除) \/xp →第二十四章 ——技术性 变量→第五卷 白名单→第五十一章 boss栏→第八十四章、第八十五章 扁平化→第一百章 标签→本书第一次大修新增章1矿词与标签 标签[记分板]→第四十八章 触发器→第九十八章 成就→第一百一十七章 常加载区块→第三十二章、第九十七章、第一百二十章 村民→第十六卷 参数→第二十九章 朝向→第九章、第二十六章、第六十四章、第六十九章、第七十五章 多人游戏→第六卷 队伍→第四十七章、第四十六章 方块→第三十章 非门→第九十三章 附魔→第五十七章、第五十八章、基岩版玩家的级锋利的苹果 复制→第五十六章 f3→第十五卷 或非门→第九十四章 或门→第九十三章 局部坐标→第五十八章、第七十五章 绝对坐标→第五章 格式→第七章 规则→第十二章 黑名单→第五十二章 火球→第一百四十六章 红石比较器→第九十一章 红石高频→第九十二章 红石逻辑组→第九十五章 红石脉冲→第九十二章 红石信号→mc新手要学习的基础—1—红石信号 箭→第一百四十五章 java版原始json文本→第十七章、第十三卷 进度→第一百一十六章 计分板→第五卷、第一百一十九章 记分板→第五卷、第一百一十九章 结构→第七十九章、第八十章、第八十一章、第八十七章、第八十八章 结构方块→第七十九章、第八十章 json→第十七章、第六十章、第十三卷 json文本→第十七章、第六十章、第十三卷 基岩版json组件→第一百零二章 基岩版原始json文本→第六十章 矿词→矿物词典 盔甲架→第九十六章 矿物词典→本书第一次大修新增章1矿词与标签 逻辑门→第九十三章、第九十四章 逻辑组→第九十五章、第九十九章 粒子效果→第三十九章 目标选择器→第四章、第二十五章、第二十六章、第四十九章 模块→第九十九章 命令方块→第二章、第六十二章、第九十五章、第九十九章 命令方块矿车→第六十二章 命令块链→第二章、第九十九章 命名空间id→第八十九章 模式→第十一章 nbt→第五十四章、第五十八章、第十一卷、第十四卷、第十六卷 难度→第六十六章 耐久→第一百零三章 npc→第十六卷 ooc→第六十二章 拼图方块→第八十七章 骑乘→第六十二章、第八十九章 区段→第二十八章 区块→第二十八章 权限等级→第六章 时间→第十九章、第六十六章 世界边界→第六十五章 snbt→nbt 实体→第二十二章、第三十一章、第一百一十二章、第一百一十三章、第十四卷 生物→第一百三十章、第一百三十一~一百三十四章 生物群系→第二十一章、第六十七章 生物事件→第六十六章、第七十八章 声音→第六十三章 同或门→第九十四章 天气→第二十章 调试→第十五卷 调试棒→第一百五十二章 调试界面→第十五卷 uuid→第四章、第一百一十章 我的世界游戏版本→mc新手要学习的基础—2—minecraft版本的区分 websocket→第一百一十五章 玩家权限→第六章 物品→第八章、第二十六章、第一百零二章、第一百零三章、第一百零四章、第一百零七章、第一百零八章、第一百零九章 物品显示属性→第一百零四章 相对坐标→第五章 与非门→第九十四章 异或门→第九十四章 蕴含门→第九十四章 与门→第九十三章 原始json文本→第十七章、第六十章、第十三卷 颜色代码→第三章、第十七章 游戏规则→第十二章 游戏刻→第二十七章 游戏模式→第十一章 音乐→第八十六章 坐标→第五章、第五十八章、第七十五章 自定义交易→第一百五十三章~一百五十六章 状态效果→第五十五章 准则→记分板 本书第一次大修完成感言 今天,2022年11月5日,本书的第一次大修正式完成。 此次大修原计划是修到第十三卷『java版的json』,但迫于时间原因只修到了第十一卷『nbt时代』完。虽然辛苦是辛苦,但最终的结果很喜人——自序言开始到第十一卷,大部分章节经过修改甚至重写后,错误大大减少,文风也更加严谨。并且,许多章节的低质量内容被替换为其他更应该讲的内容。比如第八十六章『mobevent-不想要流浪商人?关掉就可以了』,由于所讲的指令\/mobevent过于简单,章节内容就被替换成了讲解基岩版新指令\/music,而原本的内容被移到了第六十六章『指令大杂烩』中。 由于改动实在巨大(具体可以前往作品相关看『本书第一次大修进程表』),有超过一半章节内容被重写,大约四分之一的低质量章节内容被替换。所以我强烈推荐还没看过更改后章节的读者重新看一遍,或许你会有一些新的收获。 第一次大修完结的pdf文档可加群下载(但不要乱传或抹去作者信息)。pdf文档的观感可能会比在线上阅读更好一些。当然,如果以后能够抽时间将本书做成一个指令教程网站可能更好。 回到正题。第一次大修虽然修了很多问题,但仍然还有很多问题没有修。所以本书可能会在2023年暑假开启第二轮大修。新一轮大修的主要内容很有可能包含: 1翻新第十二卷~第十五卷的内容 2调整章节顺序,使得内容能够更好地循序渐进 3更正新发现的错误,添加新版本的内容 4更多配图 因此,第二轮大修可能会比第一轮更加辛苦。 接下来本书将会尽可能保证最低一个月一章的更新量(以防止被阅文平台屏蔽)。接下来几卷的内容也大致定了下来: 第十七卷——了解data指令 第十八卷——了解方块实体和方块状态,并更深入了解data指令 第十九卷——综合运用nbt、json 第二十卷——初识算法 作为一个可能很冷门的minecraft指令教程,自2020年1月初偶然间产生的一次想要写教程的想法以来,本书的第三个年头也要到头了。 最后,希望2023年,本书能够帮助更多读者学习指令,minecraft能够继续向前发展,世界也将变得更好。 本章到此结束! 序言 (于2022年8月1日修改补充) 《minecraft》是一款由马库斯·阿列克谢·泊松(markus persson),也就是我们常说的notch,创办的mojang工作室开发的一款沙盒游戏。2014年时,notch将整个mojang卖给了微软。而现在,你正在看我介绍这款叫做minecraft的游戏。 看到书名时你应该就知道了,这本书的内容是关于minecraft中指令的使用教程。至于为什么你会在一个99.99%的书都是小说的阅读平台上看到这本游戏工具书,这就说来话长了。 注意!本书不是个游戏同人小说,就是个正儿八经的游戏教程。本教程适用于minecraft各阶段玩家(云玩家、新手、普通玩家、大佬、萌新),并且最好至少要有一些minecraft的基础知识(如创造和生存模式分别是什么东西,minecraft游戏的基本玩法是什么等)。 本书前期作者写得不好,目前正在翻新修改(比如这个序言就翻新好多遍了),你可能会发现有纰漏之处,欢迎指正。本书所讲到的指令涵盖: minecraft java1.4.2~1.19.1 携带版(minecraft: pocket edition)1.0.5~基岩版(minecraft:bedrock edition)1.19.10 你可以加入qq讨论群(太冷了): 那minecraft中的指令到底是个什么东西?(已经知道的可以跳过,下面一大段都是给刚入门minecraft的新手或没玩过minecraft看的,玩过一段时间minecraft的人应该非常清楚。) 你大概应该知道编程是个什么东西吧?在编程中,你需要通过一行行代码来实现一些功能和流程,然后再由这些不同的功能和流程,加上亿些优化,就写成了一个简单的程序。而指令,虽然从狭义上来说并不是个编程语言,但从某个方面上来说,它本质上也确实有点类似于编程。 但是这又跟我们本书有何关系呢?答案当然是有关系,但这是我们几百章之后的内容了。 所以指令到底是个什么东西?通俗的来讲是这样的:你养了一条狗,为了使这只狗听话,你就需要一次次的训练它,让它对你说的某些特定的话或特定的行动产生条件反射。比如你每竖一次中指,就示意这只狗跑向你,久而久之,当这只狗看见你竖中指时,不需要你的示意,它就自动跑到你的身边来了。在这里,你的“竖中指”行为,就是一条指令,而这条指令会被指令接受者接收并执行,即“狗看见你竖中指然后跑到你身边”的行为。这就是“指令”这个词的基本含义。 如果把这只狗换成minecraft(这里没有任何贬低mc的意思),那指令在minecraft的作用你应该能想到吧?通过某种方式发出特定的一串字符,就会让minecraft做出一些事情,比如不保存并退出游戏(?minecraft没这个指令吧?)。 当然,minecraft并没有反射弧,所以minecraft中的指令和对狗发出的指令有些不同。具体的不同在于——minecraft中的指令,可以设定“参数”。 什么是“参数”呢?我们知道,狗能理解这个指令并做出相应的动作是长久以来训练而成的。但像狗这种训练出的动作有个缺点——不会变通,即你并不能竖一个中指然后指了指十米开外的张三想让狗跑到张三身边,它仍然还是跑到你身边。放到minecraft中,这就相当于是向minecraft发出“杀死张三”的指令结果把自己给杀了(根据狗的思维方式,minecraft只能理解“杀死”,但忽略了“张三“。并且因为“杀死”这条指令的效果是“杀死发出指令的人”,最终就导致你去世了) 狗的思维凭借我们目前的技术还改变不了,但minecraft的程序都是人写的,自然就要防止这种情况,让指令变得更加有用,于是就有了“参数”。参数可以在有限的范围内自由修改,这就增加了指令的自由度。有了“参数”后,“杀死张三”这条指令在minecraft接收到时就会将其拆成两部分:1杀死2张三。“杀死”被minecraft理解为将要执行的动作,“张三”被minecraft理解为这动作要执行在一个叫“张三”的东西身上。于是,你成功把张三给杀了。其中,“张三”就是这条指令的参数,你可以将“张三”改为“李四”,甚至是“王五”,再执行,就会杀死不同的玩家。 也就是说,指令本质上只是一串可以让minecraft做出特定反应的文本。指令的执行过程简单来说也仅仅只有如下四个步骤: 执行者(如玩家)发送指令给minecraft→minecraft对收到的指令进行解析→如果指令语法正确则执行指令→返回指令执行结果 在minecraft真正的指令中,上面的“杀死张三”正确的写法为“\/kill 张三”。这些内容你会在后面的章节中详细地了解到。如果你成功理解了上面对指令的描述,接下来几十章的内容你应该也能够成功理解。 注:如果你直接跳过了前面的内容,直接就看到了序言这,还请先往前翻看看『作品相关』内的『阅读本书需注意事项』一章) 第一章 作弊与输入指令 (2022年7月5日有修改,此章节写作时作者使用的minecraft为基岩1.17.0正式版[非网易版]和java1.12.2) 新建世界的时候,java版点击“更多世界的选项...”,基岩版点击“编辑设置”-“游戏”并向下滑,你会发现前者会有一个默认为“关”的“开启作弊”选项,后者会有一栏“作弊”,里面也有一个“激活作弊”选项。 这个“作弊”是什么回事?难道mojang还制作了官方外挂? 很明显,这并不是什么『官方外挂』,而是一个能让你拥有更高权限的选项(毕竟是『我的世界』嘛) 说白了,这个“作弊”选项,正如java版对于这个选项的描述一样(像\/gamemode、\/xp的命令),开启后可以让你在游戏中使用类似作弊一样的指令。 既然你要学习指令,那么这个选项必须开启,因为不开你就用不了! 额.....实际上.......能用,但只能用一点点(发送全服消息和发送私人消息)。 开启这个选项后,创建世界,你就可以开始输入指令了。 新手:“哎呀,不知道在哪输入指令啊。” 大佬:“你这消息咋发的?” 新手:“聊天栏发的啊,地球人都知道。” 指令最开始是从聊天栏开始。所以为了学习指令,首先就是要学习“如何正确使用聊天栏”。 第一步:打开聊天栏。 聊天栏在哪呢?如果你使用的是基岩版,看到上面那个消息图标的按钮没?就是那个,点进去,这就是聊天栏。 如果你使用的是java版,按下“t”键就可以呼出聊天栏。 第二步:研究聊天栏 基岩版的聊天栏有三个部分: 顶栏——显示这窗口名叫“聊天和命令”,点击左边的“<退出”可以退出界面。 信息栏——显示聊天的信息,最多可以保存100条。 输入栏——输入并发送信息、执行指令。左边是一个键盘图标,点击可以打开键盘;左边第二个是一个“\/”的图标的按键,点击可以快速执行特定的指令,是个人都懂得用;左边第三个按键是齿轮图标,打开可以设置信息栏显示的字样;中间的就是输入框,输入消息(指令)的地方;最右边是发送(执行)按钮,即发送(执行)信息(指令) java版的聊天栏就比基岩版的简单多了: 左下角——信息栏,光标放在上面转动滑轮可以上下滑动。和基岩版一样可以存100条消息。 下方——输入框,输入信息(指令),按enter发送消息(执行指令)。 当然,这本书作为一个指令教程书,肯定不会去研究消息到底该怎么发,而是去研究“如何打出指令”。 第三步:打出指令 为了打出指令,请尝试在空白的输入框中打出一个“\/”,不要告诉我你找不到这符号。这个斜杠是指令的前缀符号,它让游戏知道你要输入的是指令,而不是一条普通的聊天消息。 如果你使用的是基岩版,此时你就会发现,上面的聊天消息消失了,取而代之的是一堆依照开头字母排列的“白色\/+灰色英文单词”,同时还有功能的介绍;如果你使用的是java版海洋更新(1.13)及以后的版本,那么你也会发现,上面出现了许多“\/+单词”选项。 这些选项,每个都是指令。 但如果你使用的是java1.13以下版本,那么你就会发现,啥也没有发生,聊天栏仍然是聊天栏,主世界仍还是那个主世界,你也仍还是那个你,唯一变的就只有你聊天栏上的“\/“和四处闲逛的动物了。 在基岩版和java1.13及以上版本,你每按下一个字母,上面显示的单词信息就会更新。游戏会自动排除掉那些不符合你输入内容的指令,留下那些你可能要用的指令。同时,你打的指令进度也会显示在上面那些待选指令中,呈现黄色(java)或白色(基岩)。 而在java1.13以下版本,该怎么办呢? 很简单,输入完“\/”后,按一下tab键,然后就会....... \/?,\/advancement,\/blockdata,\/clear,\/clone,\/debug,\/defaultgamemode,\/difficulty \/effect,\/enchant,\/entitydata,\/execute,\/fill,\/function,\/gamemode,\/gamerule,\/give,\/help,\/kill,\/locate,\/me,\/msg,\/particle,\/ysound,\/publish,\/recipe,\/reload,\/receitem,\/say,\/scoreboard,\/seed,\/setblock,\/setworldspawn \/spawnpoint,\/spreadyers,\/stats,\/stopsound,\/summon,\/teleport,\/tell,\/tellraw \/testfor,\/testforblock,\/testforblocks,\/time,\/title,\/toggledounfall,\/tp,\/trigger,\/w,\/weather,\/worldborder,\/xp,\/reloadshaders,\/reloadchunks 继续按tab还会按照顺序切换。 (唉作者,为什么我是java 1.13及以上版本但打出“\/”时没变化呢?) (哦,那是因为指令提示默认需要按tab开启。聊天栏打出“\/”后,再按一次tab就会出现,且在你退出游戏前都会保持开启“指令提示”的状态。但如果你觉得这东西很烦,你还可以在聊天框只有一个“\/”时再次按tab,指令提示就关闭了!) 现在,你可以随便选择一个指令,照着它的提示打。 如果你正在使用基岩版打指令,并且照着上面那样做成功打完了你人生中第一条指令的开头单词,那么你的屏幕下面就会出现白色的带有<>和[]以及{}里面写满了各种你看不懂的英文字符串,这就是这条指令的格式,更确切的说是语法。只不过没有汉化是一大痛处。比如\/clear就是: \/clear [yer:target][itemname:item][data:int][maxcount:int] 如果你正在使用java1.13及以上版本打指令,并且照着上面那样做成功打完了你人生中第一条指令的开头单词,那么将不会出现什么新的东西——除非你点一下空格键,可能会出现接下来的格式提示,但也可能啥也没有。(当然,你可以尝试一下\/help指令,这个指令相当于是一个minecraft内置的指令手册,只不过对于新手来说可能有点难看懂) 而如果你使用的是java 1.13以下版本,那当你成功打完你人生中第一条指令的开头单词时,那也将不会出现什么新的东西——点一下空格键也还是如此。这时候,你就需要点一下空格然后再点一下tab,才可能会出现格式提示。 温馨提示:打指令最好还是使用java版或基岩版的windows10版本,原因有三。一是因为电脑打字快且方便,二是因为使用键鼠时,你可以使用上文提到的tab键来一键输入,这种一键输入不光是输入指令,还可以快速输入坐标、玩家名等参数,如果有多个参数还可以一直点tab来切换(java1.13及以上版本还可以使用小键盘的↑↓←→+tab来快速选择并输入)。三是因为使用键鼠时,唤醒聊天栏的方式并不只有按“t”键,你还可以直接按右shift左边的“\/?”键快速打开聊天栏并输入“\/”。 (偷偷告诉你,如果你在java版打错指令格式,游戏还会亲切的提示你这条指令的正确语法,还是中文的那种!只不过有些第一个参数就是输入玩家名的那种就没法了,只会提示你“无法找到玩家xxx”。而基岩版就只是——语法错误:意外的“xxx”出现在“\/xxx xxx”) ........ ........ ........ “不!我不想创建一个新的世界!我要使用我已经玩了多年的存档!” “但你这存档没开作弊啊” “那该怎么办?” “你是java版的,得进入游戏后在菜单里打开“对局域网开放”,然后将“允许作弊”改为开再确定即可,只不过这是暂时性的。要永久还得在“选择世界”界面选中该存档,然后点击重建,进入重建界面后点击“更多世界的选项...”,再打开作弊即可。如果你是基岩版就好了,直接在设置界面打开“激活作弊”按钮就可以了。” “啊?听起来好麻烦.....” “我告诉你,如果你不想创建副本还想永久开启这个存档的作弊,那更麻烦。具体过程如下: 1在选择世界界面选中该世界,然后选择“编辑”。在界面中点击“打开文件夹”打开存档文件夹。 2找到level.dat文件,将后缀名从.dat改为.nbt。 3找到一个minecraft 1.13版本及以上版本的服务端.jar文件 4按照第一百四十章“真正深入了解nbt-6”中的教程将该level.nbt文件转为.snbt文件。 5找到转化完成的.snbt文件,使用记事本打开,将allowmands的参数从0b改为1b,并保存。 6按照第一百四十章“真正深入了解nbt-6”中的教程将该level.snbt文件转为.nbt文件。 7将level.nbt的后缀改回.dat,并覆盖原文件。 照着上面这样做才行” “???” ........ ........ 第二章 命令方块 (本章写作时作者使用的是基岩版1.17.0版本和java1.17.1版本) (本章内容有可能有些难,推荐在游玩minecraft的情况下阅读本章) (本章于2022年7月10日进行大规模修改) 在你不知道指令的时候,你是否在玩地图的时候看到过一个五彩斑斓的方块?当你因好奇尝试去撸它的时候,你却发现:这根本撸不动! 没错,这就是我们的命令方块,英文名mand block,命名空间id为mand_block,在mc指令圈中常常被简写成cb。你可以通过\/give指令来获得它,比如: \/give @s mand_block 目前你不需要去了解这个指令到底是啥,怎么用,看下去就完事了。 如果你在输入了以上指令以后都没有获得,那么你最好去检查一下你的minecraft游戏版本。你可以尝试使用命令方块的数字id:137。(\/give 你的玩家名 137) 如果还是不行,请你看一下你的minecraft版本是否低于java1.4.2或者是携带版1.0.5。低于这两个版本的minecraft是没有命令方块的。 命令方块有三种颜色,六种方向,具体为: 颜色:橙得一批、青得一批、紫得一批 方向:东西南北上下 命令方块的硬度和基岩是一样的,都是-1。 爆炸抗性也一模一样,都是。 命令方块的三种颜色,各代表着3种不同的种类: 橙得一批的那个是脉冲,作用是你叫它动一下(接入红石信号),它就动一下(执行一次命令),并会向其指向的链命令方块发出执行信号。 紫得一批的那个是重复,作用是你叫它动一下(接入红石信号),它就没完没了地动(每一游戏刻执行一次命令,一般1游戏刻=1\/20秒),并且每动一下都会向其指向的链命令方块发出执行信号。 青得一批的那个是链(又叫做连锁),作用是你叫它动一下(接入红石信号),它不会动。它只会在收到执行信号时,将该执行信号立马传递给下一个它指向的链命令方块,然后再根据当前条件判断是否要执行。听起来似乎有点复杂?举个例子: a→b→c→d→ 其中,a是未被激活的脉冲命令块,bcd三个命令方块都是已被激活且无条件限制的链命令块。当a激活时,abcd将会同时执行指令,因为a激活时向b发出了执行信号,b收到后也向c发出了信号,c也向d发出了信号,三个链命令方块也都没有条件限制。(关于无条件是个什么东西,下面会讲到) 关于链命令方块还是比较复杂的,具体内容请到『第九十九章初识模块-简单的注册\/登录系统下』了解。 而方向的话,有什么用呢? 上面我们讲连锁命令方块时已经遇到过一次了:当你将一个未被激活的脉冲或循环命令方块(a)指向另一个已被激活的连锁命令方块(b),那么当a被激活时,就会向b发出执行信号。(注意,b以及之后的cde等一般都是连锁,作为开头的a一般是脉冲或循环命令方块) 就像下面这样(箭头即该命令方块的朝向,符号?代表此命令方块被激活,符号?代表此命令方块收到执行信号): 1a→b?→ 2a?→b?→ 3a?→b??→ 但b并不一定会执行,还得看这个b是有条件(条件制约)还是无条件(不受制约)的。 另外,只要这一串命令方块一直延伸下去,且除了第一个之外后面全都是链命令方块,那么不管这些链命令方块有没有被激活、是否会真的执行指令、指令有无错误,信号仍然会一直传递下去,直到默认指定的最大值。 我们会在以后讨论更加复杂的情况,也就是在第九十九章进行讨论。在此之前,你可以自己做做实验,猜猜规律。 需要注意,虽然通常情况下像这样一个接着一个的命令方块链是摆成一条直线的样子,但你也可以像下面这样摆成蛇形: b←a ↓ c→d→ 这也是没有问题的。 甚至你对着放,也是没有问题的: b→←a 总的来说,命令方块的方向决定了执行信号传递的方向。一串方向正确且能够正常传递执行信号的命令方块,就是一个命令方块链。命令方块链是命令方块知识点中最难的一部分,搞懂这个,你基本上也就入门了。还是那句话,我们会在第九十九章详细讨论这东西,也就是命令方块链和连锁型命令方块。 现在我们来打开命令方块。 右键(键鼠模式)、按下rt(手柄模式)或点击(触屏模式)命令方块以打开。打开命令方块要满足一定条件,java版的条件是:处于创造模式,并且玩家权限等级至少为2(正常单人游戏都能打得开);基岩版是需要操作员权限(或者说玩家权限等级至少为1)。如果条件不满足,是无法打开的。 至于玩家权限是什么东西。放心,我们会在第六章了解到玩家权限的相关内容。 打开命令方块后,java版的界面顶上是输入框,框下面是一个“o”的按钮,按了可以打开一个框,并且按钮变成了“x”,这个框用途就是“显示上次执行、检查指令的结果”。 为什么还要多出一个检查呢?检查跟执行是不一样的。当你修改完后退出界面,命令方块会自己检查一下,如果有错会显示一些信息,如果都正确那就什么也没有发生。执行的话就不一样了,执行就算正确也会显示消息。这个框在java版默认不显示,在基岩版默认显示,据说关掉可以让游戏更流畅一点。 再下面是三个选项,分别显示: 脉冲|不受制约|红石控制 这三个选项具体的用途是: 第一个显示脉冲的选项——选择命令方块种类,可以选择『脉冲、连锁和循环』,即上面介绍过的三种类型。 第二个显示不受制约的选项——这可以选择『不受制约』和『条件制约』(基岩版中是『无条件』和『有条件的』)。默认是选择『不受制约』。下面我们会详细了解这选项。 第三个显示红石控制的选项——这可以选择『红石控制』和『保持开启』(基岩版中是『需要红石』和『始终活动』)。默认是选择『红石控制』,即命令方块必须要收到红石信号后才能被激活。如果改成『保持开启』,那么命令方块将会始终处于激活状态。 『不受制约』和『条件制约』分别有什么作用呢? 我们知道,命令方块可以执行指令,而执行指令无非就两种结果:指令执行成功和失败。 命令方块其实会保留其最后一次执行指令的结果,这个保留下来的结果并不是只能被我们也就是玩家所看见,它还有三个作用: 1被其他指令探测,将结果信息输出到计分板中。 2被红石比较器探测,将指令执行成功的次数转化为红石信号强度等级。 3屁股对着这个命令方块的其他命令方块可以检测该命令方块的指令是否执行成功,并根据该条件判断自身是否需要执行指令。 前两个作用我们会在以后了解到具体用法,第三个作用其实就对应着上面的『不受制约』那个选项。 命令方块在执行前,如果这个命令方块是『条件制约』的,那么它就会检查一下它屁股对着的那个命令方块最后一次执行指令是否执行成功,如果成功才会执行。比如下面的例子: ←b←a a:循环,不受制约,始终活动 b:循环,条件制约,始终活动 a不管如何,除非游戏停止运行,它都会一直运行指令,每秒最高可以运行20次。 b不管如何,也会一直尝试运行指令。只不过由于它是『条件制约』的,所以它在尝试执行指令之前,会先检查一遍a命令方块是否运行成功,如果成功才会运行指令。 那么这有什么用呢? 假设a里面写着一条指令,可以检测半径30m范围内是否有怪物出现,而b里面写着一条能够发送警告消息的指令。如果半径30m内一直没有怪物出现,那么a的指令就会一直执行失败,虽然b也在尝试执行,但由于a一直失败,b也就不会真正执行指令,也就是不会发出警报。但如果a突然执行成功了,也就是发现怪物,那么b就会真正执行指令,发出警报。 当然,像这种由两个循环型命令方块构成的命令方块链十分少见,因为如果把b换成连锁型,也可以达成一样的效果,还可以降低一点cpu消耗,岂不美哉? 总而言之,条件制约的命令方块在运行前会检测其屁股后面的命令方块最后一次运行指令是否成功执行,如果那个命令方块最后一次成功运行了指令,这个命令方块也会运行,反之则不会运行。对于不受制约的命令方块来说,则并不会进行上述检查,而是直接运行指令。 懂了吧?如果不懂,多多实践即可。 基岩版的命令方块界面和java版大不相同——其界面有两列,左侧主要是对命令方块本身状态的一个设置,右侧主要是用于填写命令。 右侧不用多说,这里需要讲的是左侧相比java版多出来的内容。 左侧最上面有一个“悬停说明”,旧版本是“悬浮文本”。这儿是修改命令方块名字的地方,并且修改后的名字会直接作用在一些指令中,比如\/say。而且,正如其言,这个名字还会悬浮在命令方块上面,只不过用这个是无法做出浮空字的,因为这个浮空字仅仅会在玩家指向该命令方块时才会出现。你也可以使用铁砧重新命名命令方块,并且这个方法java版同样适用。 命令方块的默认名字在基岩版1.8.0及之后的版本是“!”,在java版和基岩版1.8.0以下版本默认是“@”。 在“需要红石|始终活动”选项的下面,还有一个“执行第一个已选项”的按钮和一个“已选项中的延迟”框。这两个东西的作用如下: 执行第一个已选项——命令方块类型为循环时可用,默认开启。开启将会让命令块在激活后立即执行指令,关闭则会先延迟“已选项中的延迟”设定的时间,再执行。即: 开启——激活命令方块→执行→等待x游戏刻→执行→等待x游戏刻→执行...... 关闭——激活命令方块→等待x游戏刻→执行→等待x游戏刻→执行→等待x游戏刻→执行...... (x值为“已选项中的延迟”的值,1游戏刻=1\/20秒) 已选项中的延迟——所有命令方块类型均可用,默认为0,单位为游戏刻。对于脉冲和链命令块来说,就是指定激活命令块到执行指令的延迟。比如设定为5,那么: 激活→等待5游戏刻→执行 对于循环的命令块来说,就是设定每次执行指令执行的间隔时间。比如设定为6,且关闭执行第一个已选项,那么: 激活命令方块→执行→等待6游戏刻→执行→等待6游戏刻→执行..... 循环型命令方块不管延迟是0还是1,结果都是延迟1游戏刻。而脉冲和链型命令方块则不同,延迟是0即按下就立马执行,1的话还是会延迟1游戏刻。 现在,让我们尝试在输入框中输入点东西。注意,命令方块中输入指令,“\/”前缀是可以省略的,因为不必和普通聊天消息作区分。在java版1.13及以上版本中,命令方块中输入指令也会有像聊天栏中输入指令一样的提示;1.13以下的版本虽然没有提示,但也可以通过tab键补全。 接下来你就自行研究吧,还是那句话,第九十九章我们会重新来研究命令方块链。 要不然最后我们留点作业吧? 还是算了,毕竟现在你也不会写些指令。 (一天,张三把一个命令方块放到了一个矿车,然后.......) [附表:命令方块历史] java 1.4.2——加入命令方块 1.5——红石比较器会输出命令方块成功运行的信号,命令方块可用铁砧重命名 1.6.1——命令方块现在无法在生存模式中和爆炸中破坏 (冷知识,在java旧版本,生存模式也可以打开命令方块,并且可以破坏) 1.7.2——加入了“显示上一个输出”框,并将命令方块字符上限重256增加到了,用修改器最大可达 1.8——发射器会放置命令方块,命令方块内字符上限达到了 1.8.6——发射器不再放置命令方块 1.9——加入了连锁、循环型命令方块和方块朝向、条件制约模式、保持开启和红石控制模式。操作权限等级小于2的玩家无法放置命令方块 1.12——命令方块链中的链命令方块现在在同一游戏刻中执行,并加入了maxmandchainlength规则以规定命令块链的最大长度 携带版\/基岩版 1.0.5——加入命令方块 1.8.0——更改命令方块默认名称重@到! 1.12.0——加入了已选项中的延迟和执行第一个已选项 第三章 § (2021-2-2有大幅度修改) 在minecraft中,有这么一个神奇的符号: § 这个符号叫做“分节符”,在现实中常见于上公开课时,老师会在黑板上写: §(内容) 在现实中§是这样用的。那在minecraft中呢? 先不要急着用,因为我们还不知道: 如何打出§ 打出§的方块有两种: 1大部分输入法可以打出§: -百度输入法windows:→工具箱→符号大全→搜索“分节符” -百度输入法android:→符→#+=→长按and符号(由于起点特性,该符号会显示乱码) -百度输入法华为版:→?123→更多→长按and符号 -搜狗输入法windows:→工具箱→符号大全→搜索“小节” -搜狗输入法android:→符→12.特殊→找一下就有了 -苹果ipad os系统自带输入法:→.?123→长按and符号 -苹果iphone os系统自带输入法:→123→#+=→长按and符号 -win10自带微软拼音输入法:win键+v打开剪贴簿→“符号”→常规标点第一项 -qq输入法windows:→工具箱→符号→特殊符号→第二阵第六行从左往右第十列 -qq输入法android:→符→特殊→找一下就有了 -讯飞输入法windows:→设置→特殊符号→特殊符号→第二阵第四行从左往右第七列 2可以使用系统快捷键来打出§: windows:按住alt,然后依次点击小键盘的0167,再放开alt (注意,直接在网页输入该符号可能会引起浏览器跳到主页,甚至有些浏览器打不出来) mac os:按住option,然后按下6,最后放开option linux:pose+s+o 你可以去按照上面的方法试一试。 现在我们就可以研究§在minecraft中的用法了。 §在minecraft中更专业的叫法是“格式化代码”、“颜色代码”。 在minecraft中,输入§,在它后面加上一个特定的符号,再写上一些内容在后面,你就会发现这些内容的颜色或者是格式被改变了。具体如下: \/\/颜色代码\/\/ §0 黑 §1 深蓝 §2 深绿 §3 湖蓝 §4 深红 §5 紫 §6 金 §7 灰 §8 深灰 §9 蓝 §a 绿 §b 天蓝 §c 红 §d 粉红 §e 黄白 §f 白 §g 硬币金[仅基岩版] \/\/格式代码\/\/ §k 乱码 §l 加粗 §m 删除线[仅java] §n 下划线[仅java] §o 斜体 §r 重置文字样式(包括颜色) 举个例子,比如你在手机上玩网易租贷服,看到了这么一段话(后面括号内容为此段话的格式): 公告(深红,斜体,加粗) 一.禁止开g(黄白,加粗) 二.请遵守小游戏规则(黄白,加粗) 三.举报请找管理员,管理员24小时在线(绿) 四.服务器q.q.q.u.n:(金,加粗) 那么这段话其编辑时很有可能是这个样子: §4 §o §l公告§r §e §l一.禁止开g 二.请遵守小游戏规则§r §a三.举报请找管理员,管理员24小时在线§r §6 §l四.服务器q.q.q.u.n: (注意,格式代码必须用在颜色代码之后,不然颜色代码会覆盖格式代码) 现在我们知道了如何打出§和§在minecraft的用法。但如果你是个java版玩家,你可能会发现一点: 在聊天框打不出§啊! 这是为什么呢?因为在java版里,§是个非法字符,打不出来,甚至在服务器打§还有可能会被踢出去。 那java版哪里可以用§呢? 写书时(指书与笔)、创建世界填写名称时、填写一些外部配置文件时、开发模组时等少数情况会用到(大部分情况下需要将§转换为\\u00a7,不然会出错)。 在书与笔中,你可以打出§,只不过并不会显示。这时候你就可以在后面添加特定字符来实现一些文字效果。 但基本上§在java版就这个用(更多内容可以到第一百二十四章-json的格式元素里了解)。 第四章 目标选择器 (本章写作时作者使用的是java1.12.2、1.17.1和基岩1.17.0) 这里有一只牛。 我们要用指令锁定这头牛。 但怎么锁定呢? 你在命令方块界面可能见到过这段话: 用“@p”来代表最近的玩家 用“@r”来代表随机玩家 用“@a”来代表全部玩家 用“@e”来代表全部实体 用“@s”来代表执行实体 (这段话在java新版本被移除了) 这段话中所讲的东西,就是指令中常见的一个参数类型:目标选择器。 目标选择器,顾名思义就是选择目标,而目标就是minecraft中的“实体”。不懂实体是什么?minecraft wiki对实体的定义是:『包括在minecraft中所有动态的、移动中的对象』。简单且不严谨地来说,实体指的是非方块的东西,比如玩家、生物等都是,还有例如掉落的方块、点燃的tnt也是实体。 目标选择器的本质就是通过一系列的参数指定筛选的条件,然后游戏根据给出的条件对所有实体进行筛选,进而得到指令执行的作用目标。通过目标选择器,我们可以指定指令执行时所产生的效果会在哪些实体上奏效。比如我们一开始就提到的\/kill指令,这条指令就可以使用目标选择器来选择哪些实体会被杀死。 实际上我们也可以不用目标选择器指定目标,反而使用玩家名称或实体uuid(uuid是一串很长且随机生成的字符串,每个minecraft实体都有一个唯一的uuid以便游戏区分)。但这两个东西,一方面效率低下,另一方面不能自动化。下面就是一个例子: 假设此时有一名玩家,其名称叫做“jie灬挥刀乱砍”(如有同名,纯属巧合),玩家uuid是“5409be4a-6333-4912-ab5bbfe3c“。如果他想要用指令给自己一个钻石块,还不用目标选择器指定,就要这么写: \/give jie灬挥刀乱砍 mand_block 或者是这样写: \/give 5409be4a-6333-4912-ab5bbfe3c mand_block 使用目标选择器,只需要: \/give @s mand_block 其中,@s就代指了执行该指令的实体。 命令方块中的介绍有点过于简单,还是得具体介绍一下: @p——代指距离执行地点最近的玩家,包括死亡玩家,如果没有执行地点,默认是主世界坐标(0,0,0)的地方,一般来说这种情况只会在服务器控制台执行指令时出现。关于坐标会在下一章讲到。 @s——代指执行指令者,不管执行指令者是否已经死亡。如果执行指令者不是个实体,比如是个命令方块,那么将会什么也不会发生。 @a——代指所有玩家,包括已经死亡的玩家 @r——随机选择一位玩家,包括已经死亡的玩家 @e——代指所有实体,不包括已死亡实体 @c——代指自己的吉祥物[仅教育版] @v——代指所有吉祥物[仅教育版] @initiator——代指正在与该npc交互的玩家[仅基岩版],不管这名玩家是否在交互时被杀死 最后一个@initiator是一个比较新奇的东西,它无法用在除基岩版npc以外的地方,关于基岩版的npc以后的章节会讲到。 第五章 坐标 你创建了你人生第一个生存存档,打算一直玩下去。进入游戏,你发现你出生在了一个大草原,太阳刚刚从地平线升起,阳光照进远处炊烟袅袅的村庄里,村民们都开门前去上班。 很快,你撸了一棵树,用泥土搭建了一个房子。但时间过得很快,10分钟的白天很快就过去。当太阳的最后一抹光消失在天边,你突然意识到——我的泥土房子呢? 此时你已经跑到了一个积雪的桦树林里,周围看起来没有一丝人烟。左手边有一座大雪山,雪山山腰上有一个矿洞。往前走是一个悬崖,从悬崖上眺望,只能看到无边无际的树林和缓缓升起的圆月。 你往回跑,但僵尸骷髅已经开始生成。它们在你背后穷追不舍,你加速奔跑,但很快饥饿值只剩三个鸡腿——你跑不动了。 空中缓缓飘落下点点雪花,你此时已经走投无路。望着正朝你缓缓走来的僵尸和在不远处正拉弓的骷髅,你突然心生一计——你朝着脚底挖了3格,然后把头上用泥土填掉,这太完美了! 时间不知道过了多久。当你挖开泥土的时候,清晨的第一缕阳光照进了洞中。你刚想欢呼,但随即而来的箭清零了你最后一滴血。死前你看到了这只箭的主人——一个躲在桦树下的骷髅。 现在我们来研究一下你为什么会这样。答案其实非常的简单——你迷路了。 为什么你迷路了呢?因为你没有记录你房子所在的位置。 那么该怎么确定你房子的位置呢? 我们知道,现实世界中,主观的确定位置方式是“上下左右前后”,客观的确定位置方式是“东南西北”。在地理课上,你还会学到目前为止最常用的确定位置的方式——经度和纬度。 经度和纬度为什么可以确定位置呢?其实,经度和纬度的本质其实是球面坐标系。 我们平常接触到的坐标系是平面直角坐标系。但不管是平面直角坐标系还是球面坐标系,它们都是在一个面上的坐标系,即二维坐标系。二维坐标系中只有两个数轴:x轴和y轴,它们互相垂直,且共用一个原点。平面坐标系的两个数轴一同使用可以表示平面上任何一个点。 这就是一种确认位置的方式。 现在我们可以尝试使用平面直角坐标系来确定你在mc中的位置。我们先设定一个原点,比如原点就在你房子,然后设定一个单位长度就是一个方块的边长,x和y轴互相垂直且平行于每个方块的边缘,整个坐标系所处的平面平行于minecraft大陆。此时你就会发现,你死的地方的坐标是: (716,-27) 这太令人震惊了。如果你早一点知道的话,或许就不会跑那么远,也不会找不到回去的路了。 但或许我们并不需要这么麻烦去自建一个坐标系。因为mc本身就自带一个坐标系。这个坐标系有三个轴。一般来说,有三个轴的坐标系,是三维坐标系(专业说法为空间坐标系)。在三维坐标系中,三个轴分别是x、y和z。minecraft坐标采用的是三维坐标系中的“空间直角坐标系”。空间直角坐标系通俗的来说就是在平面直角坐标系上加入了一个垂直于平面的z轴,用于确定点所在的高度(或宽度)。比如,在经度和纬度已经确定的情况下,再加上一个海拔高度,就可以确定你是在天上坐飞机还是在地下采矿了。 mc自带坐标的三个轴表示的分别是: x坐标——东(+)西(-)方向 y坐标——海拔高度 z坐标——南(+)北(-)方向 需要注意的是,在真正的空间直角坐标系中,高度可能是y轴,也可能是z轴。 似乎我们一般用x和z轴就可以了。确定高度的y轴,除了确定是在天上地下,还有啥用呢? 你如果到处跑来跑去,会发现主世界的海平面都是在y=64的地方(java早期版本是y=63);翻翻论坛,你会发现大家都在说钻石矿在y=12层挖钻石最好挖;挖矿时掉进岩浆,你会发现y=11层及以下的矿洞都被岩浆填满。(听说1.17最新快照版本世界最下面已经到了y=-64的地方了) 每个方块、实体都可以用坐标精准定位。而且,minecraft的坐标可以精确到小数点后面很多位。 说了这么多,那么如何查看坐标呢?java版需要按下f3(或fn+f3)打开调试面板,基岩版可以在设置界面找到“显示坐标”,打开即可,只不过基岩版需要管理员权限,java版所有玩家都可以。 然后你就会发现你的泥土房子的坐标是: (62,68,21) 但坐标就只有这一个用途吗?其实不然。 在指令方面,坐标可以确定指令执行的位置、放置方块的地点、传送的地点、生成实体的位置等等。 mc自带的坐标我们已经了解得差不多了。但如果我们在此坐标的基础上,继续使用刚才我们以房子为原点的坐标并将其改善为类似于mc的空间坐标系会怎么样? 其实不会怎么样,只是会上这本书。 但如果你不以房子为原点,而是以你自己为原点会怎么样? 你会发现,由于你会移动,导致以你为原点的三个坐标轴也会移动,最后导致以这个坐标标记的房子,其坐标的三个数值也会变化。 但你有没有发现,不管你怎么移动,你客观上的南面十米还是南面十米,并不会因为你朝南面走十米就变成南面零米了。 在mc中,这种坐标有一个特殊的名字,叫做“相对坐标”。 在相对坐标中,虽然东南西北仍然是固定的,但原点却不是固定的。就比如上面的“南面十米”,你朝南面走十米,你南面十米的方块也就变化了。 那如何表示“南面十米”呢? ~~~10就可以了。 表示相对坐标,需要在我们刚才了解的mc自带坐标的基础上,再在数字前面加上“~”,如果数字为0直接把0省略。比如往东6米,再往下1米,最后往北12米,就可以表示为: ~6 ~-1 ~-12 注意了,顺序不能乱排,目前的这两个坐标都是按照xyz的顺序排的。而且,xyz三个值要用空格分开(基岩版没那么严格,java版不用空格分开会报错)。 相对坐标是这样的。但既然这个坐标叫相对坐标,那么之前我们了解得那个坐标叫啥呢? 绝对坐标 相对坐标和绝对坐标通常情况下是可以配合使用的,因为不管你怎么动,xyz三个轴还是能跟绝对坐标的xyz对上的。举个例子: 37 ~15 ~-2——x=37的地点,再以你的绝对y坐标往上15格,然后再以你的绝对z坐标往北2格的方块。 如你所见,配合的时候,实际上就是将玩家的绝对坐标xyz值提取出来,再加上波浪号后面的数字。直观的表现为我们把你的绝对xyz坐标值分别设定为x、y和z,然后代入: (37,y+15,z-2) 就是这么个东西。 (注:相对坐标的原点实际是因指令而异的,在大部分情况下原点即是指令执行的位置,但也有特殊的情况,如java1.13版本之前的\/tp指令。) 第六章 玩家类别与权限等级 在之前一直有提到“管理员”“成员”等玩家类别名称,其实玩家在基岩版一共分为三种。基岩版的玩家权限组从高到低分别是“管理员”、“成员”、“游客”。 管理员——可以使用指令,拥有一切成员的权限,可以更改其他人的权限。可以通过\/op和\/deop来给予和消除其他人的管理员权限(java版同样适用)。在菜单栏中直接更改某人的玩家类别到管理员是暂时性的,这个人退出再重进就会重置这个人的玩家类别。使用\/op指令直接给予才是永久性的。 成员——可以使用一些指令,目标选择器只能使用@s和指定玩家名。可以破坏、放置方块,使用方块,攻击生物以及攻击玩家,能捡起物品。一般的玩家刚进入游戏是成员,管理员可以在游戏菜单栏中更改默认玩家类别。 游客——这个就惨了,只能到处观光,不能放置、破坏方块,不能攻击玩家和生物,不能使用方块,不能捡起物品,况且!基岩版的游客玩家仍然是个玩家,有基础的血量和饥饿值,但是别的玩家可以攻击他,他不能攻击别的玩家(好惨),一个木门加一个泥土墙就可以把它关起来(更惨),遇见怪物不能攻击,活活被打死(哎呀这太惨了),就算什么东西也不会找上门,迟早也会被饿死(我滴妈呀这已经不能用“惨”字来形容了)。 成员和游客可以使用一部分的指令,这一部分的指令是啥呢?它分别是\/help、\/?、\/tell、\/me、\/w、\/msg和\/list,这些指令以后会慢慢的讲。当然,成员是可以使用“§”的,所以还是可以更改消息颜色的。 刚才有提到管理员可以使用\/op和\/deop来给予和撤销其他人的管理权限,但有一点要注意的是这两个指令是不可以使用命令方块执行的。 基岩版的玩家类别是可以在暂停界面查看、修改甚至可以自定义的,但是要注意一点,就是这个面板还有一个作用,这个后面会讲到。 那么java版的权限跟基岩版是一样的吗? java服务器的根目录有一个叫做: server.properties 的配置文件,使用笔记本打开可以更改服务器的配置。 而在里面就有一栏参数: op-permission-level 其默认等级是4,可以更改数字。 如果你把这栏参数用生草机翻译一下,那么你就会知道它的作用就是: 设置op的默认操作权限等级 而这个数字,就是操作权限等级,实际上,在java版,严格点来说,有五类操作权限等级: 0——不可放置命令方块,玩家默认进入服务器就是这类权限。 1——可以无视出生点保护,破坏出生点周围方块,但无法使用命令方块。 2——可以使用所有单人游戏作弊指令(除了一些不能在服务器上运行的指令),可以使用命令方块。 3——可以使用大部分指令,包括op、ban这些指令。 4——可以使用全部指令。 为什么java版要单独分出这么多等级呢? 实际上在基岩版也是一样,因为这儿是权限等级,而刚刚介绍的那个基岩版权限是玩家类别(更准确的来说是玩家权限组)。玩家类别不等于权限等级,而权限等级也不只是玩家才拥有。 minecraft中的所有指令、玩家,以及一小部分特殊实体和方块,都有自己的权限等级。权限等级如上所述,是从0到4一共五个等级。权限等级有如下的基本特性: 1.权限低的东西无法使用权限高的东西 2.权限等级的数值越大,权限就越高 上面说过\/op和\/deop指令无法被命令方块执行,这是因为\/op和\/deop的权限等级为3,而命令方块和命令方块矿车的权限等级在java版是2,在基岩版是1。 下面列出了一些东西的默认操作权限级别: java服务器控制台——4 java服务器玩家默认权限——0 java服务器默认op权限——4 java命令方块和命令方块矿车权限级别——2 java大多数实体、方块权限级别——2 java大多数指令权限级别——2 \/op、\/deop权限级别——3 函数默认权限级别——2 \/execute子命令权限级别——2 单人、局域网游戏房主权限——4 局域网游戏在开启作弊情况下所有玩家权限——4 在基岩版中,由于并没有出生点保护的存在,所以其权限等级和java版有一些差别: 0——与java版一样。玩家权限菜单中未打开“操作员命令”时玩家所有的权限。 1——相当于java版的2级权限。 2——相当于java版的3级权限。 3——相当于java版的4级权限。玩家权限菜单中打开“操作员命令”时玩家所有的权限。 4——服务器控制台权限。 下面列出了基岩版一些东西的操作权限级别: 基岩版服务器控制台——4 基岩版命令方块和命令方块矿车——1 \/op、\/deop——3 函数默认权限级别——1 游客、成员——0 操作员(管理员)——3 \/execute子命令——1 大部分实体、方块、指令——1 现在你是否觉得玩家类别和权限等级有些复杂?对于初学者来说这确实有点复杂,但在服务器上这只是最基础的权限管理方法。当你想要开一个更大的服务器的时候,你就会发现这点权限根本就不够用。 如果可能,在以后我会讲到一个更复杂也更好的玩家权限管理办法,即:用户组与权限节点 (luckperms:?) 第七章 指令的格式与指令执行的三要素 (本章的指令并不是原版真实存在的指令,而是作者瞎编的。) 在学习指令之前,你还得了解一下指令格式的语法,不然到时候看不懂格式别怪我。 minecra官方的指令格式有六种术语、三种括号(基岩版是两种)。一种是<>(安卓客户端会乱码,建议用网页版或ios客户端,不然接下来你怎么看指令格式啊?),另一种是[],还有一种是。具体的内容如下: 纯文本-照着写即可(如\/server info中的info参数) <参数描述>-必填,根据括号内对参数的描述填写(如\/name <玩家>中的“玩家”参数) <参数描述|参数描述>-必填,选择括号内其中一项填写,符号“|”在这里表示“或”的意思(如\/drop <物品id|方块id>中的“物品id或方块id”参数) (第一项|第二项)-必填,选择括号内其中一项参数填写(如\/learn (math|physics)中的“math或physics”参数) [参数描述]-选填,根据括号内对参数的描述填写(如\/set [坐标]中的“坐标”参数) [第一项|第二项]-选填,选择括号内其中一项填写(如\/find [item|entity]中的“item或entity”参数) 在基岩版中,并没有“(第一项|第二项)”这样的指令格式,而是“<第一项|第二项>”。并且,基岩版的参数描述也有特定的格式:“描述内容:值类型”。如“方块坐标:int”,在这边int就是参数填的是整数数值的意思(实际上int这个值类型并不完全是这样的,具体的内容会在以后nbt的教学中讲到) 需要注意:本书中文指令格式较为混乱,且并没有完全按照minecraft本身的指令格式,因此建议真的要查指令格式还是到minecraft wiki。至于为什么不完全按照minecraft本身的指令格式,因为刚开始写本书的时候没怎么注意[doge]。 目前我已经在改善本书的指令格式,现在的情况已经好很多了。 本书采用的指令格式大体是这样的: 纯文本-同官方 <参数描述>-同官方,但部分旧章节会采用一些奇奇怪怪的括号,如“《》”和“〈〉”。 (第一项|第二项)-大部分章节还是采用类似基岩版的尖括号包裹。 <参数描述|参数描述>-同官方 [参数描述]-同官方 [第一项|第二项]-同官方 [参数描述|参数描述]-选填,根据括号内其中一项对参数的描述填写。 [<参数描述|参数描述>]-同『[参数描述|参数描述]』 [<第一项|第二项>]-同『[第一项|第二项]』 参数描述- java版和基岩版混用 除了指令格式的语法外,你还得了解一下指令执行时的三要素:执行位置、执行者、参数。 执行位置——简单来说就是指令执行的位置,你可以通过一个问句来理解它:这条指令在哪里运行? 执行者——就是执行指令的东西,你也可以通过一个问句来理解它:执行这条指令的人是谁? 参数——就是你给指令提供的参数,你还是可以通过一个问句来理解它:执行这条指令的人要对什么东西干什么事情? (注:指令本质上并无对这三个东西有三要素之称,这里只是为了方便大家理解给它们套了个头衔) 这三要素有什么用呢? 如果你用过mcreator这个软件来创建指令,你会发现创建指令后mcreator要求你写一个指令运行时的流程(也就是游戏解析并运行指令的过程),同时游戏将给这个流程提供以下信息: entity -执行指令的实体(对应“执行者”) xyz -执行指令的x、y、z坐标(对应“执行位置”) world -执行指令的维度(还是对应“执行位置”) cmdparams -提供的参数(对应“参数”) 也就是说,一条指令执行的时候,肯定会被提供以上信息。 其中『参数』我们得稍微讲一下。 我们在序言中讲解参数时是通过举例的方式,并没有给其下一个明确的定义,所以其实我们还是不知道参数究竟是什么。 所以参数究竟是什么呢? 参数(parameter),又称元素(elements),是指一条指令中除指令开头的单词和前缀外,提供的其他信息。 比如在指令\/tp @s ~~~~20 0 true中,前缀『\/』和指令单词tp(有些指令教程也叫做指令头,反正怎么叫都可以,没有一个固定称谓)之外的『@s』目标选择器,相对坐标『~~~』,旋转角度『~20 0』和安全检查模式『true』均为参数。 参数按照其作用,可以笼统地分为六类: 子命令——有些指令,比如scoreboard会有很多的作用,此时就需要子命令来将不同的作用区分开来。(为什么不叫子指令呢?) 位置(坐标)——指令执行的地点,也就是上面的三要素之一,一般是一个坐标 目标——指令所操作的对象。如果对象是实体,一般用的是uuid、玩家名或目标选择器;如果对象是方块,一般用的是坐标;如果对象是其他的一些东西,一般就会用一些特殊的id。 (注:本书中,默认将uuid、玩家名和目标选择器合并起来。所以后面如果你看到一个参数可以填写目标选择器,那就大概率也能填写玩家名和uuid) 值——这东西无法很好的定义,因为在不同的指令中,值类型的参数的作用不一致,但大多数情况下的作用都是具体化对目标的操作。比如在『将玩家传送至一个地点』的指令中,这个地点的坐标就是一个值类型的参数。当然你其实并不需要现在就将它理解得十分透彻,后面学习的过程中你慢慢就会懂了。 模式——对目标进行操作时,所采取的模式。比如传送玩家的时候,你可以选择是默认模式,还是开启安全传送模式。 nbt、json——一般位于指令的末尾,对目标进行更具体的选择或进行一些更高级的操作。 一条指令大多数情况下可以填写多个参数。参数与指令开头的单词还有其他参数之间在大多数情况下要有一个空格予以区分。例外情况是基岩版的相对坐标和目标选择器,参数内一般不会包含空格。 所以空格在指令中十分重要,千万要记住了! 这就是本章的全部内容。接下来我们将会步入正式的指令学习阶段。 mc新手要学习的基础—1—红石信号 (此章节的内容我不是很满意,不推荐你阅读此章节) 最近我想了一下,发现不对第一卷补点基础那是不行的,估计有读者是玩mc的新手,所以这边就得向这些新手科普一下。 那么今天直接切入正题——什么是红石信号(知道的请跳过) 红石信号,从某种意义上来讲,它类似于现实中的电能。 至于为什么是类似,是因为:红石能会把爱因斯坦气死。 为什么会把爱因斯坦气死呢? 首先,请你打开mc。 然后,在创造模式的背包里找到拉杆(也可以使用“搜索一下,你就得到”之物品栏搜索)。 接着,找到红石粉(具体方法见上一段——如何找到拉杆) 最后,把拉杆放在地上(不是按q丢出去),然后在相邻的方块上铺上红石粉。 那么现在,请你花费一点点的时间,拉下拉杆。然后你就看到最神奇的一幕: 红石粉亮了。 这是什么原理呢? 拉杆拉下,产生了15级红石信号,被红石粉(红石能的载体)吸收,红石粉就充满了能量。 只不过你不用担心会被红石能红石死,mojang没加入这个死亡方式。 你也不用担心红石线路会短路,拉杆可不是电池。 为什么拉杆不是电池却可以产生红石信号呢? 答案很简单:mc有能量无限定律(气死那位正在吐舌头卖萌的科学家) 这就是红石信号。 其实红石信号也是有等级的,级数越高能量越大,红石粉就越亮。 每级红石信号每随着红石粉传播一格,能量就要-1级。 当然有个附加条件——只要这个红石信号大于0级。 但其实红石信号的等级并没有关系到要用红石能的机器,不管是1还是15级,只要被红石连上,只要有红石能,就可以运行。 比如第二章的命令方块。 当然,红石信号的等级一般来说也有一个上限:15级。 注意!上一句话只是一般,到后面八九十章的时候会讲到红石信号的等级上限不止15级。 当然,那是以后的事了。 ok这一章到这里就结束了。 mc新手要学习的基础—2—minecraft版本的区分 (本章节偏题比较严重[doge]) 在前面的章节中,你会发现作者一口一个java版基岩版的。可能你不懂java版和基岩版到底是什么东西,它们的区别是什么,它们可以在哪些设备上运行。如果你知道了,直接跳过也没关系。如果你不知道,那你就得好好了解一下了。 说到minecraft的版本,就不得不提一下minecraft的历史发展过程。 2009年4月29日,barth发布了一款名叫无尽矿工(infiniminer)的游戏。这款游戏一开始很受欢迎,但因为源代码泄露,仅不到一个月,无尽矿工就停止了更新。 就在这短短的一个月内,有一个叫markus persson的人发现了这款游戏。这款游戏给了他灵感。很快,他就以之前被放弃的rubydung为基础,结合《无尽矿工》的代码与他的灵感,搞出了一款游戏:cave game。 这个人对你来说非常陌生,但他的minecraft用户名你不可能不知道。 他的minecraft用户名叫做notch,这款cave game就是minecraft最初的版本。 从2009年5月10日cave game开始开发到2011年5月25日出现minecraft携带版的消息为止,期间所有的minecraft版本都是基于java7和8开发的,这种基于java语言的minecraft版本就是java版。 java版被视为最经典的minecraft版本,也是第二容易入正的minecraft版本(注册mojang账号时那个验证码要挂梯子)。由于java版是minecraft年龄最老的版本,所以minecraftjava版的更新在绝大多数的时候都会比基岩版要快一些,游戏内容(特别是指令)和mod、资源包、材质包、光影资源也比基岩版多了不知道多少倍。 需要注意的是,现在我们说的minecraft java版在1.12.2更新之前,其实叫做minecraft pc版,1.12.2及之后的版本由于基岩版的出现才被重命名为minecraft:java。 java版的玩家可以一直停留在一个特定的java版本(如java1.12.2),也可以一直玩最新版本,前者情况的玩家会比较多。java版本身游戏并没有正盗版之分,只有账号和服务器进入条件有分正版和盗版(有些java服务器会开启正版验证,如hypixel和2b2t)。 2011年8月16日,mojang在xperia y平台首次发布了minecraft携带版alpha 0.1.0。此后,android(2011年10月7日)、ios(2011年11月17日)、fire os(2012年9月13日)、windows10(2015年7月29日)、gear vr(2016年4月27日)、apple tv和fire tv(2016年12月19日)也轮流发布了minecraft携带版。 你估计没有听说过minecraft携带版,就算听说过你估计也搞不懂minecraft携带版与minecraft基岩版是什么关系。别担心,很快你就能搞懂了。 minecraft携带版简单来说就是minecraft在手机系统上的版本,它基于c++开发,并且最终售出的份数比同时期的java版还要多。唉,为何要说“最终”呢?因为minecraft携带版在2018年6月21日正式停止支持。 虽然它活了将近7年,但正式版(携带版1.0末影更新)的发布已经是2016年12月19日了。minecraft携带版的内容最初相比java版来说很少,但正式版发布后携带版的内容总算是赶上了java版的主要内容,指令什么的就不用说了,结构方块都有了,并且可以游玩服务器、登录账号、购买材质包皮肤等。 唉,如果你了解过携带版,你可能就会发现,作者说的携带版和你认知中的携带版有那么亿点不同。实际上,现在网上所能找到的携带版,基本上都是携带版的alpha版本,还是及其早的alpha版本,这就导致许多minecraft玩家认为携带版及其简陋,甚至连地狱、指令都没有。真实的携带版,在正式版出来过后,已经极其完善了。 如果你玩过现在的基岩版,你可能也会疑惑——这携带版怎么和基岩版听起来差不多呢?这就要说到携带版与基岩版的关系。 携带版1.1探索更新之后的1.2版本,即独乐不如众乐更新,将标题永久的更改为了minecraft。同时,游戏也被重命名为了minecraft:基岩版。 惊不惊喜?都知道minecraft基岩版是基于minecraft携带版开发的,但没想到一个版本更新,携带版改一下名字,就成了基岩版了!携带版虽然停止支持了,但没有完全停止支持,而是换了一种方式去支持。 但为什么minecraft携带版要改为基岩版呢?因为mojang想要用minecraft基岩版将各平台打通,此时“携带版”这个名字就不合适了,所以改了个名字。 由于minecraft:基岩版的出现,有另外一个minecraft版本被影响到并最后和携带版一样被基岩版替代。 2012年5月9日,minecraft tu1版本发布在了xbox 360主机上。这个minecraft tu1版本,就是minecraft原主机版的开端。 minecraft原主机板的定位和它的名字一样,是属于游戏主机上的minecraft。继xbox 360之后,minecraft原主机版还发布在了ps3(2013年12月17日)、ps4(2014年9月4日)、xbox one(2014年9月5日)、psvita(2014年10月14日)、wii u(2015年12月17日)、nintendo switch(2017年5月11日) 原主机版的游戏内容更像是minecraft java版,但它有许多奇特的特性: 1.具有分屏功能 2.内容相比同期的java版要少一些 3.自动合成 4.具有教学模式 5.世界大小有限 6.下界:主世界为1:3(nintendo switch版为1:6) 7.皮肤不可自定义 8.创造模式飞行没有惯性 9.超平坦世界中,下界也是平坦的 10.统计数据被排行榜代替(除wii u版和nintendo switch版) 在minecraft:基岩版出来之前,java版、携带版和原主机版是minecraft的三个大版本。在这三个大版本之外,还有许多小版本,这些小版本受支持的时间并不长,并且也比较冷门,这里就不展开讲了: minecraft 4k:2009年12月2日~2014年11月(web端、java)[java] minecraftedu:2011年~2016年1月19日(windows、mac os、linux)[java] minecraft:树莓派版:2013年2月11日(linux[仅arm]、树莓派)[c++] new nintendo 3ds版:2017年9月13日~2019年1月15日(new nintendo 3ds)[c++] 2014年9月15日,mojang被microsoft以25亿美元收购,同年11月5日,markus persson离开了mojang。 上面所列的4个冷门minecraft版本中,minecraftedu是如今minecraft教育版的前身。minecraft教育版基于携带版制作,定位是帮助学校展开编程教育。其于2016年11月1日发布于windows和mac os平台,2018年9月6日发布于app store(支持ipad os),2020年8月7日发布于chrome os。、 2019年3月27日的时候,微软宣布minecraft教育版在中国将会由京东代理。说到代理,就不得不提一下你肯定知道的: minecraft:中国版(又称minecraft:网易版) 2016年5月20日,微软、mojang和网易联合宣布,mojang将minecraft基岩版中国大陆地区的运营权授予网易旗下子公司,为期五年(后来java版也授予了)。然后就是大家所熟知的水立方发布会(2017年4月7日)。hypixel服务器也借着这波热潮,于2017年5月21日宣布开放hypixel中国区,一直到2020年6月30日关闭服务器。 中国版具体有什么就不用说了,是个中国玩家都玩过,特别是手机端,熟悉得不能再熟悉。只不过现在的中国版是个啥情况,懂得都懂。 2017年9月15日,中国版手机端在app store上线。五天后的20日,携带版\/基岩版1.2独乐不如众乐更新在除nintendo switch版外(延迟到2018年6月21日)的全平台发布。但这并不是基岩版的首次发布,它最早于19日发布于xbox one,替代了原来的xbox one minecraft原主机版。 基岩版替换掉了携带版之后,原主机版也渐渐被基岩版替代。2018年6月21日,基岩版登陆nintendo switch;2019年12月10日,基岩版登陆ystation 4。到目前为止,基岩版的windows10、android、ios、ipad os、fire os、ps4、nintendo switch版本仍在接受更新,xbox one还在运营,剩下的samsung gxy apps、windows phone、apple tv、gear vr、windows10 mobile、fire tv版本全都停止支持。你现在玩的minecraft,只要是在手机上的,肯定就是基岩版。 mojang用了基岩版打通了多平台的minecraft,但由于平台太多,导致基岩版在每个平台都有些不一样。基岩版在村庄更新前一直比java慢一拍,村庄更新后,基岩版和java版更新实现了同步,甚至有些超越(比如1.17更新时山羊是基岩版先出的),版本号也统一了。 基岩版由于平台太多,导致既是最容易入正的minecraft版本(windows10版,microsoft store直接可以买),也是最不容易入正的现阶段还在支持的minecraft版本。如果你要入正基岩版,可以参考一下mcbbs(我的世界中文论坛)的入正教程。 附表1:minecraft基岩版\/携带版大更新名称 携带版alpha0.14-主世界更新-2016年2月18日 携带版alpha0.15-友好更新-2016年6月10日 携带版alpha0.16-boss更新-2016年10月21日 携带版1.0.0-末影更新-2016年12月19日 携带版1.1.0-探索更新-2017年6月1日 基岩版1.2.0-独乐不如众乐更新-2017年9月20日(switch为2018年6月21日) 基岩版1.4.0-水域更新第一阶段-2018年5月16日 基岩版1.5.0-水域更新第二阶段-2018年7月10日 基岩版1.6.0-幻翼、缓降-2018年8月28日 基岩版1.7.0-\/scoreboard-2018年10月15日~16日 基岩版1.8.0-熊猫-2018年12月11日 基岩版1.9.0-掠夺者-2019年2月6日 基岩版1.10.0-篝火-2019年3月19日 基岩版1.11.0-村庄与掠夺-2019年4月23日 基岩版1.12.0-相机-2019年7月9日(android为2019年7月10日) 基岩版1.13.0-狐狸-2019年10月29日 基岩版1.14.0-嗡嗡蜂群-2019年12月10~11日 基岩版1.16.0-下界更新-2020年6月23日 基岩版1.17.0-洞穴与山崖-2021年6月8日 附表2:minecraft:java大更新 1.0.0-冒险更新-2011年11月18日 1.1-刷怪蛋、超平坦、多语言-2012年1月12日 1.2.1-丛林-2012年3月1日 1.3.1-村民交易、冒险-2012年8月1日 1.4.2-骇人更新-2012年10月25日 1.5-红石更新-2013年3月13日 1.6.1-马匹更新-2013年7月1日 1.7.2-改变世界的更新-2013年10月25日 1.8-缤纷更新-2014年9月2日 1.9-战斗更新-2016年2月29日 1.10-霜炙更新-2016年6月8日 1.11-探险更新-2016年11月14日 1.12-多彩世界更新-2017年6月7日 1.13-水域更新-2018年7月18日 1.14-村庄与掠夺-2019年4月23日 1.15-嗡嗡蜂群-2019年12月10日 1.16-下界更新-2020年6月23日 1.17-洞穴与山崖第一部分-2021年6月8日 1.18-洞穴与山崖第二部分-预计2021年年末 第八章 give的用法 现在我们来学习第一个指令:\/give \/give指令可以说是极其基础的指令,很多minecraft玩家都用过它,因为通过\/give指令可以获取到一些创造模式中无法获取的方块物品,比如大名鼎鼎的命令方块。 下面来介绍一下: \/give 作用:可以给予一名或多名玩家物品。 需要权限等级:java-2,基岩-1 需要作弊:是 格式: \/give <玩家:目标选择器><物品id:字符串>[<物品数量:整数>][<物品数据值:整数>][nbt标签]——java1.13以下 \/give <玩家:目标选择器><物品英文id:字符串>[<物品数量:整数>]——java1.13及1.13以上 \/give <玩家:目标选择器><物品id:字符串>[<物品数量:整数>][<物品数据值:整数>][附加标签:json]——基岩版 好的,现在来逐一介绍一下。 玩家——也就是一个选择玩家作为目标的目标选择器。 物品id——什么是物品id呢?id(identity document),中文翻译“身份标识号”,相当于物品的“身份证”(专业说法是“命名空间id”)。每个物品都有自己独一无二的id。 id有数字形式(数字id)和字符串形式(英文id)。在java1.8版本以前,minecraft中的大多数事物都采用数字id,其中就包括物品和方块。java1.8版本更新后,虽然数字id仍然存在,但很多地方都被更加先进也更好记的英文id替换掉。比如钻石在java版的数字id是264,很不好记,更新后的英文id是“minecraft:diamond”,其中的“diamond”就是钻石的英文,对于会英文的玩家来说就极其方便了(特别是由于添加了命名空间前缀,大大降低了模组物品id重名的可能性)。 在基岩版,数字id和英文id两者在大多数指令中都是通用的。比如后面会讲到\/effect(状态效果),其中的状态效果id就可以使用数字id或和英文id。但需注意,物品id和方块id仍然只认英文id。也就是说,这里的“物品id”参数,除非你在使用java1.8之前的版本,你就必须得填入物品的英文id。 java1.13更新后的java版本,完全抛弃了“数字id”,全面使用英文id。因此,你现在在minecraft wiki上只能找到基岩版的数字id,而不能找到java版的。要找到java版的,就需要打开页面历史记录,找到1.13版本尚未更新时的页面,才能找到java版的数字id。 物品数量——这个不用说了吧,哪个中国人不会看中文的? 物品数据值——这个就有意思了,mojang为了“偷懒”,将同类物品集合到数据值中,比如说羊毛,不输入或输入-1默认是白色,即相当于输入0,如果要获得其他颜色就需要输入其他值。 数据值为-1相当于数据值为0,因为数据值默认就是0,而-1的意思是“不考虑数据值”,所以数据值填-1同等于不填。 在java版1.13版本更新中,数据值被删除(但没有完全被删除,讲nbt时会讲到),每个物品也就有了自己对应的英文id。比如红色羊毛在1.13版本之前其id是:wool 14。之后就变成了red_wool。 附加标签——这东西类似于nbt标签(实际上是json),以后会讲到。 ok,说了这么多,来举个栗子: \/give @a diamond_block 1 这个的指令意思是给予所有玩家一个钻石块(diamond_block)。 现在来献上一些不能在创造模式的背包中获取的物品吧! mand_block——命令方块(脉冲型) barrier——屏障方块,又称空气墙 air——空气方块,也没啥用,就算输入成功也获得不了(空气嘛,你能抓住吗?) (本书的qq群入群问题就是\/give @s air有什么用,因为air获取不了,所以这条指令啥用也没有) structure_blocks——结构方块,一个神秘的方块,以后会有几个章节专门讲这个东西。 structure_void——结构空位,基岩版新版本有了,结构方块的配套方块。 —————————————— \/give的历史 java版(alpha) v1.0.15——加入了\/give。但只能使用数字id,且只能获得单个物品。格式(可能):\/give <玩家名><物品> ?——加入了数量参数。格式(可能):\/give <玩家名><物品>[数量] java版 1.0.0[beta 1.9-pre4]——加入了损害值(数据值)参数 1.3.1[12w16a]——能在单人游戏中使用了。 1.7.2[13w36a]——加入了nbt标签参数。 [13w37a]——现在可以使用物品英文id了。 1.8[14w03b]——现在不支持物品数字id了。 [14w32b]——现在无法突破物品堆叠上限。 1.12——当目标选择器是玩家自己时,实际上会使用@s选择器。 1.13[17w45a]——移除了数据值和nbt标签参数。 1.17[21w10a]——加入了数量限制。 携带版(alpha) 0.16.0[build 1]加入了\/give。 第九章 tp-传送指令 (此章最后一次大修改于2022年7月9日) 我相信在看这本书的你一定去玩过私人服务器,里面最经常使用的指令就是tp(传送)。 minecraft固有的传送指令是\/tp,其全称实际上是teleport。由于这条指令深究起来很复杂,加上目前还是学习初期,我们就先了解个皮毛就好。 \/tp 作用:将一个实体传送到另一个实体或者是坐标。 需要权限等级:java-2,基岩-1 需要作弊:是 格式: \/tp [传送目标:目标选择器]<目的地实体:目标选择器> 这可以将选定的目标传送到另一个实体的位置,比如把张三传送到李四的位置。注意,目的地实体不能为多个,即你并不能将张三传送到李四和王五的位置(就算张三不止一个也不能这样干)。如果将传送目标省略,那么将会传送执行者自己(一般是你自己)。 \/tp [传送目标:目标选择器]<一个地点:坐标>[<水平旋转角度><垂直旋转角度>] 这可以将选定的目标传送到一个指定的地点。 那什么是水平旋转角度和垂直旋转角度呢? 水平旋转角度(yrot),又叫做y轴旋转角度,指的是实体以y轴为中心,俯视时顺时针的角度。听不懂?没关系,你只需要打开你手机,然后找到一个应用叫做指南针(一般手机有自带)。没有?也没关系,百度地图高德地图之类的总该有吧?或者你现场下一个指南针,甚至自己用磁铁做一个,只要有标上角度就行。 打开指南针,你就会发现在这个指南针的外侧有一圈度数,以正北(0°)开始,顺时针绕一圈360°再回到正北。 这个度数叫做什么呢?叫做真北方位角。相应的,以正南(0°)开始,也是顺时针绕一圈360°再回到正南的,就是真南方位角。 由于我们位于北半球,所以常见的是以正北为0°,也就是采用真北方位角的指南针。但这又和我们水平旋转角度有何关系? 其实,我们的水平旋转角度就是minecraft版的真南方位角——以实体为中心,以正南(z轴正方向)为0°,顺时针下来,实体朝向和正南方向的夹角(也或者说实体在真南方位角体系中朝向的角度),就是该实体的水平旋转角度。 比如你看向正北,你的朝向按照真南方位角来看,就是朝向180°,你的水平旋转角度就是180°;朝向东北,就是朝向225°,你的水平旋转角度就是225°;朝向西南,就是朝向45°,你的水平旋转角度就是45°....... 懂了吧?如果还没懂......网上随便去找一个以正南为0°的指南针的图片,把minecraft的坐标怼上去就清楚了(以后再考虑为这个教程弄点图片)。 另外的垂直旋转角度(xrot),又叫做x轴旋转角度,指的是实体与水平面之间的倾斜角。这个可比水平旋转角度好理解多了,相信你应该能够看懂上面的这句话。只不过需要注意一点,对于有头或有眼睛的实体来说(比如玩家),这东西指的是头的朝向(也就是目光的朝向)与水平面之间的夹角,而不是整个身体(这就是为什么你能够看到一个头倾斜着的玩家,但你绝不可能看到一个身子倾斜着的玩家) (有没有一种可能,其实minecraft中的玩家朝正下方或正上方看的时候,实际上是平行与地面的,只是mojang懒得做出这样的效果而已) (唉,这样子就能解释为什么在游戏中,第一人称的玩家看不到自己的下半身了!) 需要注意的是,这个垂直旋转角度虽然以水平面朝向为0°,但和上面的水平旋转角度不一样的是,这东西引入了负值:朝上为负,朝下为正。比如你头朝上45°看天空,那么你的垂直旋转角度就是-45°;你头朝下45°看地板,那么你的垂直旋转角度就是45°。而且,垂直旋转角度肯定不能超过+90°或低于-90°。 懂了吧?在tp中引入垂直旋转角度和水平旋转角度,就可以指定传送目标在传送完成后的朝向(如果未指定,将会不改变朝向,虽然可能没多大作用,但在一些rpg地图或服务器,能够让玩家一传过来就看到重要的告示牌或其他的一些东西,那岂不美哉?) 比如下面的指令: \/tp @p ~~~ 90 0 这将会使最近的玩家朝向正西而不改变其位置。 很简单吧?对了,既然坐标有『绝对坐标』和『相对坐标』,那么旋转角度有没有『绝对旋转角度』和『相对旋转角度』呢? 答案是肯定的。 和相对坐标一样,相对旋转角度也是使用符号~代表传送实体本身的朝向,以正数和负数代表角度的增加和减少。比如下面这条指令: \/tp @p ~~~~-30 ~1 假设这@p选中的还是上面那位被迫朝向正西的玩家,那么这条指令将会使他朝向南偏西60°,头微微朝下1°。 简单吧?本章也就到这里了,对于初学者来说这些内容就已经足够了。 上面所述的tp指令适用于基岩版和java版。在java版1.13版本更新之前,tp的指令用法就这么多。而关于1.13版本到底对tp进行了怎样的更新,这些内容以及一些更加复杂的东西会在第六十四章具体讲到。 —————————— \/tp历史 -java版 ssic server 1.7——加入\/tp indev 0.31——移除了所有命令 alpha v1.0.16_01——重新加入了\/tp。 正式版 1.3.1——现在允许玩家传送到指定坐标 1.8——加入了朝向参数。 1.9.3——\/tp不能在能将玩家传送到y=-512到512以外的地方。 1.10——y轴限制现在增加到-4096到4096。 1.13——将\/tp和\/teleport同化,\/tp也正式成为\/teleport的别称(缩写)。 -携带版(alpha) 0.16.0——加入了\/tp。 ....... ....... 你有没有发现,这个tp指令的旋转角度参数的格式是这样的: [<水平旋转角度><垂直旋转角度>] 这是什么意思呢? 这个的意思就是,这两个参数都是选填的,但如果你填写了其中的一个,另外一个也就必须填写,即你并不能只填写水平旋转角度或只填写垂直旋转角度,而把另外一个空着。 知道了吧?那么本章到这里就完全结束了。 第十章 kill-熊孩子最喜欢的指令 我的世界网易服务器,最不缺的是什么?是石头?是泥土?是空气?答案是熊孩子! 一进入网易的生存私人服务器,宛如进入了中国版2b2t一样,地图遍地狼藉,房子七零八落,偶尔还能看到流淌的岩浆。 幸亏熊孩子们还只会用tnt,如果它们知道了指令,那么或许这将会是它们最喜欢的指令: \/kill (额,其实就算知道了也没权限) 相信大家对这个指令都不陌生。就算你不知道,这种死亡信息你总见过吧: xxx 掉出了这个世界(基岩版为xxx 失败了) 今天,我们就来看看这个指令,也就是\/kill。 \/kill 作用:清除一个或多个实体。 权限等级:java-2,基岩-1 格式: \/kill [实体:目标选择器] 好的,现在来解读一下。 如果你不写要kill的实体,就执行\/kill,会发生啥? 很明显,你死了。 执行\/kill不填目标选择器=自杀,也就是默认选择执行者自己作为指令执行的目标。很多指令都有这样的特征,不写目标相当于选取执行者自己作为执行目标。 什么?你并没有死? 哦,那你一定玩的是基岩版的新版本,因为基岩版中处于创造模式的玩家被\/kill是死不了的。 但是加上目标选择器就不一样了,你想杀谁就杀谁。 但事实上在minecraft中,\/kill本意是“清除某个实体”,所以使用\/kill后,你会发现其消息栏中有一个“已清除xxx”,并不是死亡。 —————————— \/kill历史 java版(alpha) v1.2.6——加入了\/kill命令。 java版 1.6.1——\/kill命令对实体造成的伤害从1000增加至3.4x10的38次方。 1.8——为\/kill命令加入了玩家和实体参数,同时能被命令方块执行了。 1.8——为修复编号为mc-的bug,\/kill命令现在直接清除非生物实体,不再对其造成3.4x10的38次方虚空伤害。 1.13——目标选择器参数不再是可选。 1.15——目标选择器参数再次可供选择。 携带版(alpha) 0.16.0——加入了\/kill命令。 第十一章 gamemode-更改游戏模式 我相信玩过minecraft的java版的玩家,一定很熟悉这个指令,它就是\/gamemode。 \/gamemode,单词是gamemode,由game和mode两个单词组成。game意思是“游戏”,mode意思是“模式”,拼起来就是游戏模式(gamemode)。 \/gamemode 作用:更改单个或多个玩家的游戏模式 需要权限等级:java-2,基岩-1 需要作弊:是 格式: \/gamemode <游戏模式id:字符串>[玩家:目标选择器]——高于java1.12.2版本 \/gamemode <游戏模式id:字符串|字符|值>[玩家:目标选择器>]——低于java1.13版本和基岩版 要注意的一点是,java版从1.13版本快照17w45a开始就不支持英文缩写以及数字id了。 游戏模式大致分为四种,其中一种为java版独有。这四种分别是生存(survival)、创造(creative)、冒险(adventure)以及旁观者(spectator) 生存模式,英文:survival,缩写:s,数字id为:0。 创造模式,英文:creative,缩写:c,数字id为:1。 冒险模式,英文:adventure,缩写:a,数字id为:2。 旁观者模式,英文:spectator,数字id为:3。 在新版本的基岩版中,还有一个特殊的模式: 世界默认游戏模式,英文:default,缩写:d,数字id为:5 旁观者模式——它不等于基岩版的游客类型玩家,这种模式的玩家可以穿过障碍,不受伤害,没有实体,可以像创造一样飞,并且可以附身于各种生物身上。但处于这种模式玩家是无法进行交互的。 生存模式——不用讲了吧。 创造模式——也不用讲了吧。 冒险模式——在java版中,需要使用特定的工具才能破坏方块(如剪刀剪树叶)。而在基岩版中,什么都无法破坏,这点也被用于基岩版的“服务器保护”中。 如果写的时候不填目标选择器时,会发生啥? 答案是你修改了自己的游戏模式。 没错,就是这么简单。 下面举个栗子: \/gamemode adventure @a 什么意思呢?意思是将所有玩家的游戏模式都切换成冒险模式。 ———————————— \/gamemode历史 java版(beta) 1.8——加入了\/gamemode <玩家:目标选择器><模式>。 java版 1.3.1——\/gamemode现在能在单人游戏中使用,同时语法更改为\/gamemode <模式>[玩家:目标选择器],模式可以是数字和survival、creative、s或c。\/gamemode 3更改为\/gamemode 0(生存模式) 1.8——加入了spectator(旁观者模式)。 1.9——现在\/gamemode会在聊天栏中显示玩家更改为的游戏模式。 1.13——现在\/gamemode不再支持简写。 携带版(alpha) 0.16.0——加入了\/gamemode命令,但只能使用创造和生存模式。 携带版\/基岩版 1.1.0——加入了冒险模式。 1.17.30——现在能够切换到世界默认模式了 1.18.30——为旁观者模式加入了数字id:6 1.18.31——为旁观者模式加入了spectator全称 (知道吗,java版还有两个游戏模式:极限模式和调试模式。这两类模式因为都是直接作用于世界的,所以无法使用\/gamemode更改到这两种游戏模式) (好消息好消息,基岩版的旁观模式在测试啦!) 第十二章 gamerule-自定游戏规则 每个游戏都有游戏规则,minecraft也不例外。 在基岩版,管理员可以在“设置”界面更改游戏规则,但那些游戏规则显然是不够的。 所以,如果真的要更改游戏规则,那还得用一条专门的指令。 这条指令就是:\/gamerule。 \/gamerule,和上一章讲过的\/gamemode是差不多的,都是由两个英文单词组成的指令。game是游戏的意思,rule是规则的意思,合并就是游戏规则(gamerule)。 \/gamerule 作用:更改游戏规则 需要权限等级:java-2,基岩-1 格式: \/gamerule <游戏规则id:字符串>[布尔值] \/gamerule <游戏规则id:字符串>[值] 游戏规则有很多个,在章尾我会列出来所有游戏规则以及默认是开启还是关闭。 布尔值知道吧?不知道的话我在这里科普一下。布尔值指的是“真”、“假”,常用于代码中。在minecraft中有的地方使用的是英文,即是true(真)和false(假),也可以使用二进制的1(真)和0(假)。在\/gamerule和大多数指令中,使用的都是英文。 大部分游戏规则都是布尔值类型的,即true开启,false关闭。但也有些游戏规则是一个数值。 布尔值和数值参数省略的话,即只填游戏规则,就可以获取该游戏规则当前的状态,比如: \/gamerule mandblockoutput 返回就是:游戏规则mandblockoutput目前为:true 现在我列出一些常用的游戏规则: (布尔值游戏规则) mandblocksenabled(默认:true)——命令方块在游戏中是否启用(基岩版设置界面为“启用命令方块”)[仅基岩版] mandblockoutput(默认:true)——命令方块是否在聊天框中向管理员显示执行的结果 disableelytramovementcheck(默认true)——是否禁止服务器检查玩家使用鞘翅的移动速度[仅java] dodaylightcycle(默认:true)——是否开启时间的流动(基岩版设置界面有,为“开启昼夜更替”) doentitydrops(默认:true)——不是生物的实体是否会掉落物品(基岩版设置界面有,为“实体掉落战利品”) dofiretick(默认:true)——火是否会蔓延和自然熄灭(基岩版设置界面有,为“火焰蔓延”) doinsomnia(默认:true)——幻翼是否自然生成 doimmediaterespawn(默认:false)——玩家死亡时是否直接跳过死亡界面(基岩版为immediaterespawn)(基岩版设置界面为“立即重生”) domobloot(默认:true)——生物死亡是否掉落(基岩版设置界面有,为“生物战利品”) domobspawning(默认:true)——生物是否自然生成(不影响刷怪笼)(基岩版设置界面为“生物生成”) dotiledrops(默认:true)——方块破坏是否掉落物品(基岩版设置界面为“区块掉落”) doweathercycle(默认:true)——天气是否变化(基岩版设置界面为“天气更替”) keepinventory(默认:false)——玩家死亡时是否保留数据(死亡不掉落)(基岩版设置界面有,为“保留物品栏”) logadminmands(默认:true)——是否在服务器日志中记录管理员使用过的命令,适合服务器被捣乱时查看[仅java] mobgriefing——生物是否可以破坏、放置、修改方块、捡起掉落物以及(唤魔者是否可以)把蓝色的羊变为红色。该规则不影响非生物实体,不能阻止tnt和末影水晶的爆炸。(基岩版设置界面为“生物破坏”) naturalregeneration(默认:true)——玩家在饥饿值足够的情况下是否可以自然回血(基岩版设置界面为“自然生命恢复”) pvp(默认:true)——玩家之间是否能造成伤害[仅基岩版](基岩版设置界面有,为“玩家间伤害”) respawnblocksexplode(默认:true)——玩家在非主世界维度使用床和在非下界维度使用重生锚时是否爆炸[仅基岩版][be 1.17.20更新,现在还在测试] sendmandfeedback(默认true)——玩家执行命令的返回消息是否显示在聊天栏 showcoordinates(默认:true)——是否在聊天框区域持续显示玩家所在的坐标[仅基岩版](基岩版设置界面有,为“显示坐标”) tntexplodes(默认:true)——tnt是否爆炸。注意,这并不会影响到tnt矿车和末影水晶。[仅基岩版](基岩版设置界面有,为“tnt爆炸”) (数字游戏规则) randomtickspeed(默认值:1[基岩]或3[java])——每二十分之一秒(一游戏刻)每个区块中发生的方块事件的频率,简单来说就是值越大,方块变化速率越快。(基岩版设置界面有,为“随机刻速度”) 下面我说一下,随机刻的最高值是4096,也就是2的12次方。随机刻不要改太高,不然——你会被卡得够呛的。但如果你的设备撑得住,那么你将会看到万物疯狂生长、生机勃勃的景象。 spawnradius(默认值:10[java]或5[基岩])——新进入服务器玩家和没有自己重生点玩家重生时距离世界出生点的最大距离,调成0可以让玩家准确生成在世界出生点 还有一点,我说一下一个小知识,minecraft java版对于大小写的要求十分严格,而基岩版较为宽松。 ———————————— \/gamerule历史 java版 1.4.2[12w32a]——加入了\/gamerule,同时加入了dofiretick(火焰蔓延)、mobgriefing(生物破坏)、keepinventory(保留物品栏)、domobspawning(生物生成)、domobloot(生物掉落)、 dotiledrops(方块掉落)、mandblockoutput(命令方块输出)规则。 1.6.1——加入了naturalregeneration(生命恢复)、dodaylightcycle(时间流逝)规则。 1.8——加入了logadminmands(记录指令日志文件)、showdeathmessages(显示死亡信息)、randomtickspeed(随机刻)、sendmandfeedback(保存命令方块输出)规则。加入了创建虚拟规则的能力。 1.8.1——加入了doentitydrops(实体掉落)规则,同时,dotiledrops不再影响实体。 1.9——加入了spectatorsgeneratechunks(旁观者区块加载)、spawnradius(重生半径)、disableelytramovementcheck(检查鞘翅飞行)、doweathercycle(天气变化)和maxentitycramming(实体推动伤害)规则。 1.12——加入了dolimitedcrafting(配方解锁)、maxmandchainlength(命令链链上限)、announceadvancements(显示进度)、gameloopfunction(高频执行函数)规则。 1.13——不再接受未知值(自定义游戏规则)。现在会对值进行类型检查。移除了gameloopfunction规则。 1.14.3——加入了disableraids(玩家攻击)、reduceddebuginfo(简化调试界面)规则。 1.15——加入了doinsomnia(幻翼生成)、doimmediaterespawn(立即重生)、drowningdamage(窒息伤害)、falldamage(跌落伤害)和firedamage(火焰伤害)规则。 1.15.2——加入了dopatrolspawning(控制灾厄巡逻队生成)和dotraderspawning规则(控制流浪商人生成)。 1.16——现在创造世界时可以编辑游戏规则。加入了forgivedeadyers(激怒的中立生物的目标玩家死亡时,该生物是否恢复中立状态)和universnger(激怒中立生物是否攻击任何玩家)规则。 1.17——加入了freezedamage(是否承受冰冻伤害)、yerssleepingpercentage(跳过夜晚所需玩家睡觉百分比)规则。 携带版 1.0.5——加入了\/gamerule。同时加入了drowningdamage、falldamage、firedamage、pvp(玩家间攻击)规则。 1.1.0——加入了dodaylightcycle、doentitydrops、dofiretick、domobspawning、domobloot、dotiledrops、doweathercycle、keepinventory、mobgriefing规则。 基岩版 1.6.0——加入了doinsomnia规则。 1.7.0——加入了mandblocksenabled规则。 1.8.0——加入了randomtickspeed规则。 1.9.0——加入了showdeathmessages和immediaterespawn规则。 1.12.0——加入了spawnradius、sendmandblockfeedback、mandblockoutput、maxmandchainlength、naturalregeneration、sendmandfeedback、showcoordinates(显示坐标)和tntexplodes(tnt爆炸)。 1.14.0——加入了showtags(展示物品可破坏、放置方块列表)规则。不再接受自定游戏规则。 1.16.210——加入了freezedamage规则。 1.17.20——加入了respawnblocksexplode(床、重生锚是否爆炸)规则。 第十三章 clear-清除物品的指令 我们第一个提到的指令是\/give,作用是给予玩家一样物品。有正必有负,minecraft还有一条指令,和\/give完全相反,这条指令就是\/clear。 clear在英文中有三种意思,分别是: 1.清楚地;明白的。 2.清除;不再受阻。 3.离开;不靠近。 很明显,这儿的clear意指第二种,也就是“清除”。所以,\/clear的作用是:清除玩家的物品。 \/clear 作用:清除玩家的单个或所有物品。 需要权限等级:java-2,基岩-1 格式: java1.12.2之后 \/clear [<目标选择器:玩家>][<物品id:字符串>][清除的最大数量:int整数] 基岩版和java1.13之前 \/clear [<目标选择器:玩家>][<物品id:字符串>][要清除物品的数据值:int整数][清除的最大数量:int整数] 目标选择器——这个必须填玩家。不填默认为命令执行者,即清除命令执行者(自己)的所有物品。 物品名——可以填需要清除的指定物品其id,不填默认清除指定玩家的所有物品。 要清除物品的数据值——这个如果不填,即不填数量和数据值(或者数据值填-1),将会只清除所有指定玩家的指定物品。 清除的最大数量——默认是全部清除(相当于填-1),填的话可以指定一次清除最大清除多少物品。注意是最大!也就是说,就算背包里的指定物品没有达到最大数量,还是一样会被清除。 下面举个栗子: \/clear @a diamond 0 1 这个是以基岩版的格式为基础的,java版1.12.2之后版本需去掉那个0。意思是清除所有玩家物品栏里的数据值是0的钻石,并且只清除1颗。 注意,clear这条指令及其特殊,它的数据值是在数量前面的,而不是填完数量再填数据值,这点要注意! 清除的最大数量可以填0。也就是说,可以通过填0来探测一个玩家背包里是否有指定物品,比如: \/clear @p minecraft:diamond_sword -1 0 {disy:{name:“天空之脊“}} 就可以检测该玩家是否持有一把叫做“天空之脊”的钻石剑。 (没错,后面那串就是nbt,这串自定义名字的具体操作会在第一百零四章:物品的显示属性讲到) 如果该玩家并没有持有,那么将会返回: 无法清除xxx的物品栏,没有可清除的物品 如果该玩家持有一把,那么将会返回: xxx有1个符合条件的物品 可惜的是,到底有多少物品只会显示,却不会通过红石比较器转换为红石信号。 第十四章 fill-填充指令 相信用过电脑画图的都知道,画图软件都有一个功能,它就是:颜色填充。 minecraft也有填充功能,但是它要用到一个指令,就是\/fill。 \/fill,在英文里意为“填满;充满;装满;注满......”反正都是满。所以,\/fill的用处是:填满指定范围的空间。 \/fill 用处:用特定的方块填充或替换一个区域内的方块。 需要权限等级:java-2,基岩-1 是否可使用命令方块执行:是 格式: java1.12.2之后 \/fill <起点方块坐标><终点方块坐标><填充方块:字符串>[<填充模式:destroy|hollow|keep|outline|rece>] \\\\使用rece填充模式时\\\\ \/fill ...... rece [被填充方块:字符串] java1.13之前和基岩版 \/fill <起点方块坐标><终点方块坐标><填充方块:字符串>[<方块数据值:int整数>|<方块状态>][<填充模式:destroy|hollow|keep|outline|rece>] \\\\使用rece填充模式时\\\\ \/fill ...... rece [被填充方块:字符串][被填充方块数据值:int整数] 由于\/fill这个指令比较复杂,导致我们必须要用比较长的篇幅介绍完。 首先,\/fill的填充范围是一个长方体,起点方块坐标和终点方块坐标是两个点,从这两个点衍伸出来的x、y、z轴会形成一个长方体,这个长方体就是填充的范围。填充的范围包括的方块量不能超过块,不然无法执行。 需要指定填充的方块,填充模式默认是rece。比如一个最基本的: \/fill ~1 ~-1 ~1 ~-1 ~-1 ~-1 diamond_block 这将会在命令执行者(一般是你自己)脚下生成一个3x3x3的钻石块平台。 填充模式一共有五种——destroy、hollow、keep、outline、rece。 一、destroy destroy中文意思是“破坏”。所以它的作用跟破坏比较相似,是什么破坏呢? 你玩过生存模式吧,在这个模式,你每破坏一个方块,一般都会获得一些东西。比如破坏木头获得木头;破坏树叶有几率获得树苗;破坏石头会获得圆石...... 没错,destroy的作用是用指定方块替换填充区域内的所有方块,而被替换的所有方块都被视为被无魔咒的钻石锹或镐采掘而掉落成对应的实体形式,但是只能被剪刀采集的方块,如藤蔓就不会掉落,流体方块更不可能掉落,你见过拿着水方块的玩家吗?如果你玩过1.8之前的版本,可以无视上一句话。 二、hollow hollow的中文意思是“中空的;空心的;凹陷的”,其作用是仅替换填充区域外层的方块,内部方块被替换为空气。所以用这个可以快速的建造出一个中空的地方,非常适合用于建筑党和创作地图党。 三、keep keep,中文意思是“保持”。所以它的作用也是类似于“保持”的。但它保持的是什么? 填充区域内的所有非空气方块。 keep的作用是仅用指定方块替换填充区域内的空气方块,如果全都是空气方块当然是全都替换啦。这个非常适合于坑坑洼洼的地方填充东西而不破坏地形。 四、outline outline的中文意思是“概述;略述;显示…的轮廓;勾勒…的外形”。这么多意思,到底是啥呢?很明显,肯定不是“概述”,所以前面两个,去掉。 所以,这里的outline的意思是“显示…的轮廓;勾勒…的外形”。有轮廓、勾勒两个词,你想到什么? 这说明它的效果跟hollow是很像的,但是有一点不一样,就是——它不是中空的。 outline的作用是仅用指定方块替换填充区域外层的方块,内部方块不受影响。这个非常适用于将地图的一部分包起来而不破坏地形。 五、rece rece是默认的填充方式,中文意思是“代替”。 rece有更多的参数,所以上面特别列出了一个“使用rece填充模式时”的格式。 rece多余出来的参数可以指定要替换的方块,保证其他方块不受影响。这个功能很好用,特别是配上execute指令,但那也是后话了。 下面来举个例子,当然是rece的栗子: \/fill 0 45 0 55 70 55 diamond_ore 0 rece stone 0 什么意思呢?这条指令的意思是: 将在(0,45,0)到(55,70,55)的所有石头(stone)替换成数据值为0的钻石矿(diamond_ore)。 \/fill历史 java 1.8——加入了\/fill、 1.11——加入了对方块状态的支持 携带版alpha 0.16.0——加入了\/fill (唉作者,什么是方块状态?) (方块状态简单来说,就是这个方块的状态。) (?) (比如方块的朝向之类的) 第十五章 发送消息 在minecraft,如何与玩家交流,那肯定是在聊天框打字了。 但是如果得像服务器里“自动化”,那么命令方块肯定就派上用场了。 之前说过命令方块有三种文本输出形式。第一种是聊天栏显示运行结果;第二种是命令方块界面显示运行结果;第三种是给命令方块取名。 但前两种都是只能管理员查看,第三种又太短,且不美观。这时候我们就需要可以发送消息的指令。在minecraft中,可以发送消息的指令有很多种,但功能都差不多,接下来就来一一讲一下,这里先全部列出来: \/say <消息> \/tell \/tellraw \/w \/me \/msg \/teammsg \/tm(?) 首先第一个是\/say。say可以发送广播消息。发送消息的格式长这样: [xxx]xxxxxxxx 我们再来拿用聊天栏发出的信息的话来对比一下: xxxxxxx 可以发现,除了名字的显示形式是不一样之外,其他都一样。 \/say 作用:广播 需要权限等级:java-2,基岩-1 格式: \/say <消息内容> 显示信息格式: [发出人的昵称]“内容” \/say这个指令很简单,但又有些那么不简单。 \/say的消息内容不止可以写消息,还可以包括目标选择器和玩家名! 比如: \/say @p 就可以广播最靠近命令执行地点的玩家。 这功能的适用性非常广,你可以在你的rpg地图里使用\/say 目标选择器来让npc说出玩家名,也可以在服务器中检测持有违禁品的玩家并将其用户名广播。 普通玩家无法使用\/say,但这些玩家干嘛要用\/say,好好的在聊天栏内发送消息不好吗? 但mojang就这么神奇,也向普通玩家添加了一条广播指令,它就是\/me。 \/me 作用:广播(实际上mojang官方本意是显示一条关于自己正在做什么的信息) 需要权限等级:0 格式: \/me [消息内容(动作)] 显示信息格式: * username 消息内容 (username即玩家名,这儿如果使用汉字空格会没掉) 和say一样,me也可以在消息中参杂目标选择器和玩家名,只不过这功能暂且只有基岩版有,java版还未添加。me如果不填消息只会限速玩家昵称。 广播的指令暂且只有这么多。但一个游戏只有世界聊天室那肯定是不行的,所以mojang还添加了一堆用于私信的指令: \/tell \/w \/msg 作用:告诉一个或多个玩家消息。 需要权限等级:0(目标选择器只能使用@s和玩家名,其他类型选择器需要2级[java]或1级[基岩]权限) 格式: \/tell <收信者:目标选择器><内容> \/w <收信者:目标选择器><内容> \/msg <收信者:目标选择器><内容> 这些指令都很简单,也没有什么好讲的,只是需要注意权限等级不够目标选择器不能使用除@s以外选择器。 \/msg有个变种,这个变种是在java1.14版本加入的,仅java版有:\/teammsg \/teammsg即在队伍频道发送消息,可以简写为\/tm(?)、 \/teammsg、\/tm 作用:队伍频道发送消息 需要权限等级:0 格式: \/teammsg <消息> \/tm <消息> 显示信息格式: ->[队伍名]<玩家名>消息内容 关于队伍是个什么东西,讲记分板时会讲到。 第十六章 title-屏幕标题 \/title指令正如标题所言。可以在屏幕上显示标题,就像是ppt的那个大字一样。这个命令相对于之前我们学过的命令比较复杂。 \/title 用处:在单个或多个玩家的游戏屏幕上显示标题 需要权限等级:java-2,基岩-1 格式: \/title <玩家:目标选择器> clear \\\\可以清除指定玩家正在显示的标题\\\\ \/title <玩家:目标选择器>reset \\\\可以复原对指定玩家屏幕标题的渐入、保持、淡出时间的设置\\\\ \/title <玩家:目标选择器> title <主标题内容:json文本[java]|字符串[基岩]> \\\\在指定玩家屏幕正中心显示主标题,如果此时已有主标题正在显示将会覆盖该标题\\\\ \/title <玩家:目标选择器> subtitle <副标题内容:json文本[java]|字符串[基岩]> \\\\在指定玩家屏幕正中心显示主标题时显示副标题,如果此时已有副标题将会覆盖该标题。如果执行指令时并没有主标题正在显示,将会在下次主标题显示时配套出现\\\\ \/title <玩家:目标选择器> actionbar <附加文字内容:json文本[java]|字符串[基岩]> \\\\在指定玩家物品栏上方显示一些文字,如果此时已有文字正在显示将会覆盖这些文字\\\\ \/title <玩家:目标选择器> times <文字渐入时间:游戏刻><文字保持时间:游戏刻><文字淡出时间:游戏刻> \\\\可以对指定玩家屏幕标题文本显示时的渐入、保持、淡出时长进行设置,单位是游戏刻\\\\ 相信大多数人看了上面六种格式的说明,已经大致会用这条指令了。不难发现,使用\/title指令可以在屏幕上的三个地方显示文本,一个是屏幕正中心的“主标题”,一个是主标题下方的“副标题”,一个是物品栏上方的“附加文字”。这就有点像什么?没错,ppt。 让我们打开powerpoint或wps office,新建一个文档,什么排版格式都不要选,然后就是: |单击此处添加标题| |单机此处添加副标题| 没错,在minecraft使用\/title指令时显示的主标题和副标题就是这个样。 而物品栏上方的附加文字,我们只需要插入一个横排文本框,将其拖到ppt页面的“单机此处添加副标题”正下方,注意要对齐中间,然后输入一点文字,再将文字大小改到差不多12左右。没错,就是这么个感觉。 我们也可以在minecraft中使用\/title做出ppt的感觉,只需要这样子摆好命令方块: a→b→c→ 在java版中这样设置: a:循环,保持开启,不受制约——title @a title {“text“:“单击此处添加标题“} b:连锁,保持开启,不受制约——title @a subtitle {“text“:“单击此处添加副标题“} c:连锁,保持开启,不受制约——title @a actionbar {“text“:“单击此处添加文本“} 在基岩版中这样设置: a:循环,始终活动,无条件——title @a title 单击此处添加标题 b:连锁,始终活动,无条件——title @a subtitle 单击此处添加副标题 c:连锁,始终活动,无条件——title @a actionbar 单击此处添加文本 然后...... 然后你就会看到屏幕上出现了不断闪烁的主标题和副标题,只有物品栏上方的“单击此处添加文本”没有闪。 这是怎么回事? 因为标题有渐入、保持和淡出的时长。 默认这三者的时长是10游戏刻(0.5s)、70游戏刻(3.5s)和20游戏刻(1s),可以通过times来改变。因为我们要让它一直显示,我们就可以: \/title @p times 0 0 这样子我们也就不需要循环并保持开启了,直接改为脉冲、红石控制就可以了。 但是这显示的时间也太长了。如果要清除,我们此时就可以使用clear来清除标题: \/title @a clear 同时建议使用reset复原刚才对times三个值的更改: \/title @a reset 现在,我们算是把\/title六个格式都用了一遍,基本上掌握了\/title的使用方法。但我们仍然要注意一些东西。 首先副标题不会单独显示,而是需要和主标题配套显示。如果在主标题还未显示时指定了副标题,这个副标题将会在下一次主标题显示时配套出现(注意,主标题淡出后也会清除副标题)。 其次,物品栏上方的文本并不会受到times、reset和clear的影响,就像刚才作者更改了渐入、保持、淡出三者的时间,只是标题受到了影响,物品栏上方的文本仍然还是按照默认值来。而且,物品栏上方的文本重复显示时并不会闪,而是好端端的正常显示。这两点需要注意。 最后需要注意的是,java版的title其文本使用的是json文本,所以刚才的指令中,java版和基岩版的指令不太一样。基岩版也有使用json文本的title指令,它是\/titleraw。上一章讲过的\/tell指令也有一个json变种:\/tellraw。关于\/tellraw和\/titleraw会在下一章以及之后的内容提到。 历史: java 1.8——加入了\/title 1.11——加入了可以在快捷栏(物品栏)上方显示文本的能力 携带版和基岩版 1.0.5——加入了\/title 1.9.0——加入了\/titleraw 第十七章 java版json文本初识 在上一章提到了json文本。json文本在学习指令前期估计只有\/title和\/tellraw会用到,所以我们这边也就先认识一下如何使用json文本显示文本内容。 json \/?d?e?s?n\/,全称javascript object notation,是一种轻量级资料交换格式。而我们今天所要了解的,叫做json文本(json text)。更确切的来说,是原始json文本(raw json text)。 需要注意,json≠json文本≠原始json文本。json有很多用途,不仅仅是拿来给你发消息用的。json文本严格来说指的是原始json文本经过识别所转化成我们人能够看得懂的文本,没有带json语法的那种,也就是最终的输出形式。原始json文本既然带有『原始』二字,那就是指还未经过识别的json文本,也就是还处于原始形态并带有json语法的json文本。 在minecraft中,java版和基岩版的json文本略有差别,但大体都相同。本章主要讲的是java版的原始json文本的使用,因为在基岩版,原始json文本在指令中使用程度并不高。我们会在第六十章讲到基岩版的json文本。 如果你还没搞懂,也没关系,看下去就完事了。 原始json文本听起来很高级,让人望而生畏,给人一种『作者似乎想要尝试教会你们』的样子,但其实它并不高级,相反还很简单。 简单到什么程度呢?看: ““ 这是一串没有任何内容的简写json文本,如果将其识别,转化为正式的输出文本格式,那将会是一串空空如也的文本。 我们可以尝试向里面加入一些东西,比如: “hello minecraft“ 这串json文本被识别后,也就是运行『\/tellraw @a “hello minecraft“』,将会输出如下内容: hello minecraft (注意,json文本的所有括号均为英文半角括号,但阅文平台会自动将英文半角括号改为中文全角括号,所以会有些奇怪) 是不是很简单?但你有没有注意到,上面我提到『这是一串没有任何内容的简写json文本』,注意『简写』两字。 所以它的真正形态是什么呢?如下: {“text“:“hello minecraft“} 别害怕,这仍然很简单。 上面这就是刚才那个『“hello minecraft“』的真正形态。我们对这个完全体进行解剖,可以得到如下内容: {——一个花括号,这个花括号告诉游戏『嘿,这里是json文本的开始!』。游戏也根据它的形态,判断出接下来将是一个json对象。 “——一个英文半角括号,这个括号告诉游戏『这里是一个字符串的开始!』 text ——一串英文。游戏暂且不知道这串英文的意思,于是它继续看下去。 “——又是一个英文半角括号,这个括号告诉游戏『这里是这个字符串的结束!』 :——一个英文半角冒号,这个冒号告诉游戏『这里是这个组件(key-value pairs)的名称与值的界限!』。游戏根据以往的经验,确认刚刚遇见的『“text“』是这个组件的名称(key),这个组件是一个text纯文本内容组件。 “——还是一个英文半角括号,这个括号告诉游戏『这里是又一个字符串的开始!』 hello minecraft ——一串内容,游戏根据前面得到的消息,确认这是这个组件的值(value)。游戏因此得知,这个text纯文本内容组件将会显示出『hello minecraft』。 “——最后一个英文半角括号,这个括号告诉游戏『这里是这个字符串的结束!』 }——又一个花括号,这个花括号告诉游戏『这里是json文本的结束!』 然后游戏根据以上信息,确认这个原始json文本的意思是:显示出一串文本(text),内容为『hello minecraft』 我们也可以根据以上信息,了解了这个json文本: 1这个json文本被一对花括号({})包围,这对花括号标志着这个json文本的开始和结束 2这个json文本内有两个内容,text和hello minecraft。这两个内容都是字符串,因此均被英文半角括号(““)所包裹着。一对英文半角括号标志着一个字符串的开始和结束。 3『“text“』是组件的名称(key),由于是字符串需要加上括号,所以其中的text才是具体的名称,意思为『文本』,标志着这个组件的值是一串要被显示出来的文本,也标志着这个组件是一个纯文本内容组件。 4『“hello minecraft“』是这个组件的值(value),由于它是一个字符串,因此要被括号包裹着,所以hello minecraft才是值的内容。这标志着这个纯文本内容组件将会显示出『hello minecraft』。 5『:』英文半角冒号是一对『组件名称』与『组件值』的分界线,其左边是名称,右边是值。 6『“text“:“hello minecraft“』像这样的由一对『名称』和『值』组成的东西,叫做『组件』(key-value pairs)。 7一个组件的名称规定了该组件是个什么东西,干什么用的。值则规定了该组件具体要干什么,怎么干。 8如果值或组件名是一个字符串(组件名肯定是),那就得使用括号将其包裹起来。 8外面被花括号所包裹着的,里面有一个或多个组件的东西,就像『{“text“:“hello minecraft“}』这样的,是一个json对象(object)。 (注:上面提到的什么『组件』之类的,是本书内才有的叫法,仅为了方便大家理解,官方并无此叫法。『组件』的正式叫法是『键-值对』,又叫做『属性-值对』、『栏位-值对』、『名称-值对』。其中,『键-值对』的英文是『key-value pairs』) 这就是json的基础语法,如果你能看懂上面的内容,那就恭喜你,接下来的内容对你来说将会相当简单。 现在我们已经知道名称叫做text的组件,是纯文本内容组件。这个组件所输出的内容是一串平平无奇的文字,没有颜色,也没有什么特效。 如果我们想要给这串文字添加更多的特效,就要了解更多的组件及其使用方法。 在minecraft java的json文本中,可用的组件可以分为两类:内容组件和修饰组件。内容组件用于规定每个json文本对象能够表现出什么样的内容,一个json文本对象最多只能有一个内容组件;修饰组件用于修饰内容组件,一个json文本对象可以拥有多个修饰组件来对输出的内容进行修饰。 内容组件最基础的是『text』,即上面接触过的纯文本内容组件。 使用纯文本内容组件,可以显示一串最简单的json文本,就像上面的那个json文本: {“text“:“hello minecraft“} 需要注意,json文本是对大小写敏感的,因此你不能写成如下的样子: {“text“:“hello minecraft“} 那样子会报错。 上面显示出来的hello minecraft是最基础的白色。如果要更改文字颜色,那么就需要使用color组件(在java版,json文本很难使用分节符)。 color的值是字符串,也就是说需要被引号包裹着。值支持17种颜色id: ck(黑)、dark_blue(深蓝色)、dark_green(深绿色)、dark_aqua(深湖蓝色)、dark_red(深红)、dark_purple(深紫)、gold(金色)、gray(灰色)、dark_gray(深灰色)、blue(蓝色)、green(绿色)、aqua(湖蓝色)、red(红色)、light_purple(亮紫色)、yellow(黄色)、white(白色)和reset(取消颜色效果使用默认颜色,一般使用于子json对象中) 比如: {“text“:“hello minecraft“,“color“:“light_purple“} 就可以显示一个浅紫色的“hello minecraft”。其中,color颜色组件修饰了text纯文本内容组件的颜色为浅紫色。不难发现,如果有多个组件,就得使用英文半角逗号将它们分开。 如果你认为这些颜色还不够,你甚至可以使用html的十六进制颜色格式来搞到更多的颜色。比如红色的十六位颜色编码就是:#ff0000,用到json文本里就是: {“text“:“hello minecraft“,“color“:“#ff0000“} 关于html十六位颜色编码的具体内容自己上百度或谷歌搜,这儿就不多讲了。 我们知道分节符§不仅可以更改文本颜色,还可以为文本添加更多的格式。那么在json中,我们该如何为一串json文本添加格式呢? §能添加五种文本格式,对应到json中即是: §k 乱码对应obfuscated模糊文本 §l 加粗对应bold粗体 §m 删除线对应strikethrough删除线 §n 下划线对应underlined下划线 §o 斜体对应italic斜体 上面的五个组件其值类型均为布尔值,也就是true(开启)和false(关闭)。 在json文本中,布尔值和gamerule一样,是使用true和false,并且并不需要添加括号,因为不是字符串。 比如要为hallo minecraft添加斜体,你就需要这样子: {“text“:“hello minecraft“,“italic“:true} 其中,italic斜体修饰组件修饰了text内容组件为斜体。你可以尝试将italic改为其他组件,比如underlined、bold之类的。 现在我们已经了解了java版json文本的基本使用方法,基本上日常使用是没有什么问题了。 不对,还有一个问题!如果要在一串json文本里前面使用一种颜色或文本格式,后面使用另一种颜色或文本格式,那该怎么办? 确实,使用花括号包裹的json文本,也就是json文本对象,就算修饰组件能够含有多个,具体下来其实每个组件也只能包含一个,还没有什么先后顺序。 那怎么办呢?能不能一次性就使用多个json文本对象呢? 答案是可以的。 我们可以将多个json文本对象排成一个阵列,组成一个json文本对象列表。 什么是列表?顾名思义,就是将各种东西列在一起的表格。在json中,列表内的内容一般都是相同类型,比如都是小数,都是整数,都是字符串,内容与内容之间用英文半角逗号分开,外侧用中括号包裹起来,这样子就形成了一个json列表。 比如下面就是一个全都是整数的json列表: [1,2,3,4,5,6] 那既然列表内可以放数字,那能不能放字符串、布尔值,甚至是json对象呢? 答案也是可以的。 比如下面这样子: [{“text“:“hello“,“color“:“blue“},{“text“:“minecraft“,“color“:“ck“},uncher“] json文本在解析的时候,会按照我们正常人所认为的顺序,即从左到右解析。这样子就可以实现hello是蓝色,minecraft是黑色uncher是蓝色。 等等,为什uncher是蓝色而不是白色? 因为在一个json列表中,列表前面的json对象定义了文本颜色,这个颜色就会传递下去,就算中途有其他对象使用了color改变了其他颜色,也只是作用在这个对象内,下一个对象还是使用这个颜色。文本格式也是一样的道理。 现在就没什么问题了吧? 需要注意一下,java1.9版本之前的json,组件名不需要额外加括号,也就是说在minecraft java1.8版本,你可以直接这样子: {text:“hello minecraft“} java json历史: 1.7.2——加入了\/tellraw,第一次有指令支持了json 1.8——加入了使用json的\/title。告示牌和成书也开始使用json文本。 1.13——自定义名称使用了json文本。加入了name参数使用json的\/bossbar指令。 1.14——物品描述标签支持json文本。 1.16——color可以使用html十六位颜色码来更改文本颜色(需要注意这个功能是这时候才添加的)。 ...... ...... ...... as we know ,we can''t type § into the chatbox. so can we type the unicode of § into the chatbox? the answer to the question is no. so can we type it by using tellraw? i can say, the way is feasible in minecraft java 1.12.2. now, let us run minecraft java 1.12.2, and create a new world in creative mode.remember to allow cheats. after the world was created ,please run the following mand: \/give @s mand_block i''m sure that you must have a mand block now.please set it on the ground. right click to open the gui,then enter the following mand: \/tellraw @p {“text“:“\\u00a7bhello minecraft“} click the done button to return the game.take a lever out of your bag.set it next the mand block. now let''s pull the lever.the moment the lever is pulled, a line of light blue text appear surprisedly! yes, as you looked, we can use the unicode of § in json text! have you learned it? if you want to learn about it more, please search “在原版中更改任意文字颜色“ in mcbbs.you will find a post by a great mand veteran in 2015. 第十八章 基岩版特殊符号 (本章于2022年11月5日进行重写) 在第三章,我们了解到在minecraft中有一个特殊的符号:分节符§。通过§,我们可以在游戏中更改文本的颜色、格式等等,甚至打出乱码。但在基岩版中,还有一些其他的特殊符号,这些符号在minecraft基岩版的界面中十分常见,你也可以在游戏中手动打出它们。 这些特殊符号究竟是什么?有什么用途?我们又该如何打出它们?请不要走开,《走进科学》(划掉)马上为你揭晓答案。 —————part 1————— 张三现在十分苦恼,这已经是他今天第十次在关闭背包或工作台时不小心点开游戏指南了。但或许是因为生存玩久太无聊,也或者只是好奇,他这一次并没有马上关闭游戏指南,而是看了下去: 『《我的世界》是一款通过堆方块............使用wasd可四处移动............快速连续按两次w或按「控制」可冲刺。按住w不放,您将继续冲刺,直到小于[鸡腿][鸡腿][鸡腿]。』 张三看到那三个代表饥饿值的鸡腿时,突然想起来了什么——好像之前在一些服务器中也有遇见过这种穿插在文本中的鸡腿图标。当时他并没有因此想到什么,但今天这样相同的鸡腿图标同样穿插在官方的帮助手册中......他突然有一个奇特的想法:是否可以在游戏中打出这些图标呢? 于是他打开了万能的bing,搜索了『我的世界特殊图标』。结果十分令人amazing啊,第一个结果就是『【我的世界】我的世界特殊符号分享_哔哩哔哩_bilibili』。按照这个视频中的方法,他复制了视频简介的内容,并将其粘贴到到聊天框中。成了!张三犹如发现一片新大陆一样欣喜。他看着这些本应出现在官方帮助手册界面的图标,思考着是否能够把这些图标用于建筑装饰中...... 所以,你现在应该明白这些『特殊符号』究竟是什么了吧?但凡只要你玩过一些大型的minecraft服务器,如花雨庭、easecation之类的,肯定见过这些符号:m币、盔甲、鸡腿.......其中,又属m币最为典型。 你可以通过复制粘贴的方法来在游戏中输入这些特殊符号。你可以前往网上搜索,也可以在这就地复制: a| b| x| y lb| rb| lt键| rt键 两个方框键﹟菜单键 ls键珅 rs键 十字上键瓅十字左键畖十字下键瘄十字右键 圆形x键羭圆形o键聕圆形方键脇圆形三角形键 l1键舼 r1键苵 l2键莬 r2键 圆形左键蓔圆形右键 l3键荩 r3键 三角形上键蛗三角形左键蝲三角形下键蛏三角形右键 圆形a键醸圆形b键鈢圆形x键铳圆形y键 方形l键 r键铩 zl键铴 zr键 减键闺加键 圆形l键雦圆形r键 圆形上键韡圆形左键韡圆形下键饥圆形右键 鼠标左键|鼠标中键 方形上键脇方形左键膢方形下键舼方形右键 跳跃键莬潜行键 飞行上键蓔飞行下键 合成提示开铳合成提示关 lg键| rg键 圆形菜单键 ls键▅ rs键 圆形l键獆圆形l左右键珅圆形l上下键 圆形r键瓅圆形r左右键畖圆形r上下键 lt键皘 rt键 win键 0键 a键苵 b键 lg键葇 rg键蓔 ls键芸 rs键荩 lt键蘾 rt键 x键蝲 y键 鸡腿锴盔甲铩 m币 教育版 朗读 蓝t 复制的话可以到qq群里下载本书的pdf文档或你上电脑版开f12,甚至你直接给浏览器装一个解除禁止复制的插件都行。 现在,你应该已经对这些特殊符号有一个大致的了解,但同时肯定还带有一些疑问。所以接下来,我们将会深入了解这些符号。 —————part 2————— mojang为何会在minecraft基岩版中搞出特殊符号这种东西?不难发现,这些特殊符号其实都是游戏中的一些图标,如方向键、饥饿值、手柄按键。之所以要使用特殊符号,本质上其实是为了方便在游戏中插入这些常用的图标。比如游戏自带的游戏指南、设置界面、手柄按键提示等等。所以这些图标本质上并不是给我们玩家用的,而是给官方以及第三方开发者所使用,以丰富游戏内容。 那为什么这些图标在游戏外部显示不出来,只是显示一个方框或叉叉甚至啥也显示不出来? 其实这些『特殊符号』在国外有一个较为正式的名称:minecraft:bedrock edition unicode characters(我的世界基岩版unicode字符)。什么是unicode?你可以把它当作是一个相当巨大的表格,表格内存储了许许多多的字符,每个字符都有一个对应的唯一的id。比如字母『m』的id就是『u+004d』,其中的『004d』是十六进制数字,翻译成十进制数就是『77』,代表这个字符在unicode表中的第77位。 unicode表十分巨大,巨大到它足以同时装下拉丁字母、汉字、日文、韩文、阿拉伯文等等一堆文字,甚至还装下了许许多多的表情、数学符号。在这种情况下,它还能预留出一大堆的空间以装下更多的字符。这些预留空间的一部分可能永远也不会被unicode官方定义,因为它们被划分为『private use area』(私人使用区)以方便其他人在有限的范围内自己定义一些字符。minecraft基岩版的这些『特殊字符』,其实就是一系列mojang自己在unicode的『私人使用区』定义出来的字符,它们只在minecraft中才能够被正确识别并赋予特殊的含义。而在minecraft之外,由于其他的应用程序并不会关心minecraft给unicode的『私人使用区』私自定义了什么东西,所以当这些应用程序遇见这些minecraft的『特殊字符』时,它们仅仅会把这些字符当作是『未知字符』而不会正确显示出来,除非应用程序自己也对它们进行了一番定义。 像这种自己在有限范围内给unicode表添加更多内容的情况其实并不少见。比如apple设备上可以显示出的苹果徽标,在安卓、windows等其他系统上就显示不出来。又比如在鸿蒙系统上的一些特殊图标,在非鸿蒙系统上就显示不出来。从本质上来说,苹果的徽标、鸿蒙的特殊图标和minecraft的特殊符号,其实都是一样的——它们都是个别组织私自定义的字符。 回到正题。相信通过上面一番解释,你应该已经了解了这些『特殊符号』的本质。接下来,让我们继续回到指令的学习中,了解如何控制minecraft中的时间。 第十九章 time-改变时间 看标题你应该就知道了,指令\/time可以对minecraft内的时间做出修改。 \/time 作用:更改、加快游戏的时间 需要权限等级:java-2,基岩-1 格式: \/time add <增加或减少的游戏刻:int整数> \/time query <要查询的游戏时间类别:字符串> \/time set <要设置成的游戏时间:int整数|字符串> \/time指令有三种格式,分别是add、query和set。 add,意为“增加”。所以,add的作用是增加游戏的时间(如果配上重复执行的命令方块,一游戏日1秒钟也可以做到)。 那么增加所用的时间单位是啥呢? 其实不填,默认是游戏刻(t)。游戏刻是啥?游戏刻是minecraft的一种游戏时间,支撑着minecraft的自然运转。1游戏刻(t)=1\/20现实秒(s)。具体关于minecraft中的时间在第二十七章有详细的讲到。 其实时间单位也支持现实秒(s)和游戏日(d),单位怎么写呢?比如“2s”,不要空格。 当你运行add一次,游戏时间会增加或减少你所填的时间。 对了,这三种时间单位的换算是: 20t=1s 1200s(20分钟)=1d 下一个:query。 query,中文意思为“疑问”或“查询”。很明显,这里不可能是前者。所以query的作用是:查询游戏时间。 query又有三种参数,分别是daytime、gametime和day。daytime指的是自当天(游戏日)日出后流逝的游戏刻数,也就是相当于今天已经过去多长时间了;gametime指的是世界总共流逝的游戏刻数,相当于这个存档已经玩了多少游戏刻了;day指的是已流逝的游戏天数,相当于这个存档中已经过了多少天(游戏日)了。query可以查询这三种时间,并返回相应的结果。 下一个:set。 set,中文意为“设置”,在很多其他minecraft指令也有出现。使用set可以设置游戏的时间。当一个世界被创建时,时间是从0游戏刻开始的。比如: \/time set 0 就可以重返世界刚生成之时。 你也可以使用一些特定的参数来跳到指定的时间: day——日出[基岩为白日](1000) noon——正午(6000) sunrise[仅基岩]——日出(?) sunset[仅基岩]——日落() night——晚上() midnight——午夜() (单位:游戏刻) 有趣的是,在java版使用set更改时间是以游戏时间为基础的,但在基岩版使用set却是以游戏日时间为基础的。比如使用: \/time set 0 在java版会将时间改为0,在基岩版却会将时间改为下一游戏日刚开始的时候。 所以在基岩版,唯一能将游戏时间拨回去的方法是\/time add 负数,来减少游戏时间。 第二十章 weather-控制天气 使用\/time可以更改时间,那么天气如何更改? 在minecraft中,能改变天气的有两个指令,分别是\/weather和\/toggledownfall,但后者现为基岩版独有。 为什么\/toggledownfall在基岩版独有呢?那是因为\/toggledownfall在java版1.13的时候被删除了。 \/weather,其单词weather的中文意思为“天气”。这么直白的指令你立马就知道了吧。 \/weather 作用:更改天气。 需要权限等级:java-2,基岩-1 格式: \/weather <天气id:字符串>[持续的时间:秒(仅java)|游戏刻(仅基岩)] \/weather query(仅基岩版) 在minecraft中,天气有很多种,有晴天、雨天、雪天、雨夹雪、雷雨天、暴风雪天以及雷雨夹雪。 但实际上只有三种,分别是:晴天、雨天和雷雨天。 为何呢?其实雪天是雨天的变种,在雪原生物群系(就是满地都是雪,水结冰的地方)雨天就是雪天。那雨夹雪是怎么回事?其实雨夹雪也是雨天,只不过是在下雨的地方和下雪的地方交叉形成的。雷雨天同理。 雷雨天就相当于晚上了,光线低导致会在地表刷新怪物(1.18预览版本除外,1.18目前的预览版本怪物需要在完全没有光线的情况下才会刷,白天的雷雨天还是有一些亮度的),当然,和晚上类似,你可以睡觉度过雷雨天,就算是白天也可以。 三个天气的id是 晴天——clear 雨天——rain 雷雨天——thunder 举个例子,更改为雷雨天就需要: \/weather thunder 但这在java版只会持续5分钟,在基岩版则会随机持续5~15分钟,因为没有填“持续的时间”参数。 持续的时间如果不填写,在java版默认是5分钟,在基岩版则默认是随机300~900秒。注意,『持续的时间』参数的单位在java版是秒,基岩版则是游戏刻。 另外,在目前java和基岩的最新版本中,『持续的时间』参数可以填写0,但效果并不一样。在java版中,这将会使得游戏的天气循环重新回到自然状态,即由游戏自己来控制天气;在基岩版的效果则和上面所提到的基岩版默认值一模一样(即随机300~900秒)。 如果你此时在地下,需要取得现在的天气情况,你可以使用: \/weather query来查询。 但目前query是基岩版独占,java版还没有。 (有趣的是,如果现在是晴天,你还使用\/weather clear更改天气为晴天,那么天气将会在五分钟后变成雨天或雷雨天,在雨天和雷雨天同理。 这就是为什么超平坦时经常下雨的原因了,因为你肯定一下雨就尝试用\/weather clear,这就导致游戏在几分钟后必然会将天气切换到雨天或雷雨天。) 现在来看看基岩版的独占指令:\/toggledownfall。toggledownfall,是由toggle(切换)和downfall(衰落)组成的单词。而downfall又是由down(向下)和fall(落下)组成的单词,所以toggledownfall的意思是:切换成向下落下的(?所以这就是切换成雨天喽)。 \/toggledownfall 作用:更改天气为晴天或雨天。 需要权限等级:je-2 be-1 版本独占:基岩版(java于1.13版本将其移除) 格式: \/toggledownfall 你的确没看错,格式就只有\/toggledownfall而已。其实这个指令的作用简单得要死,它的作用是:如果为晴天,更改为雨天。如果为雨天或雷雨天,更改为晴天。 这就是\/toggledownfall的用处。 第二十一章 一些短小但不容忽视的指令 (观前提示,如果您主要游玩的版本是minecraft1.19及以上版本,推荐您在看完此章节后也去瞧瞧第六十七章) 其实还有一些短小的指令,但却不能被忽视。本章整理了一些重要而短小的指令来讲。 一. \/seed 作用:查看地图种子 需要权限等级:单人游戏-0,多人游戏-2 独占版本:java版(电脑版) 需要作弊:否 格式: \/seed 这条指令算上斜杠也才5个字符啊。 但是它很重要,因为java版是没有设置界面的,你只能通过它来查看你的地图种子。基岩版可以在设置——游戏界面查看种子。其实,种子在minecraft也算是一种隐私,比如基岩版,所有玩家都可以看到游戏地图种子,这就导致玩家可以通过种子作弊,特别是生存服。、 到底是怎么作弊的呢? 作弊方法: 1.把种子抄下来。 2.新开一个私人创造存档,开启作弊,输入种子,进入游戏。 3.通过指令寻找要寻找的东西,找到后记下坐标,返回之前的游戏,来到记下的坐标,即可找到物品。 并且,现在有些网站也支持你输入一个种子,然后直接给你返回许多结构的信息,比如村庄啊、钻石矿啊之类的。 这样作弊是不是美滋滋?所以java版\/seed种子只有op才可以查看也就变成了合情合理的了。 历史: java beta 1.8.1——调试屏幕现在显示世界种子了 java 1.2.1——服务端不再向客户端发送世界种子信息 1.3.1——由于单人游戏和多人游戏实现方式统一,现在世界种子不再显示在调试界面上,而是添加了\/seed命令用于查看世界种子信息。 1.13——\/seed返回的信息现在可以复制到剪贴板里了 二. \/help和\/? 作用:获取指令的帮助 需要权限等级:0 需要作弊:否 格式: \/help [页码:int整数]——java 1.13版本之前和基岩版 \/help [要询问的指令:字符串] \/help指令,就是“获取帮助”指令,相当于minecraft自带的指令手册。里面包含了指令的格式,还是中文的(只不过在java1.13之前并没有中文)。 直接输入\/help在高于java1.12.2的版本会显示玩家当前可使用的全部指令和其格式,在低于java1.13和基岩版会显示指令帮助手册的第一页。指令帮助手册的指令是按照字母表顺序排列的,可以在\/help后写上数值跳转到对应的页码。 也可以使用\/help直接询问一个特定的指令(注意不用带斜杠),比如: \/help help(吃瓜群众:禁止套娃!) 这条指令的意思是询问help指令help有啥用(无聊人才会干的事),然后\/help会在聊天栏显示这条指令的格式。 \/?作为\/help的简写指令也是相同的用法。 历史 java 1.3.1——加入了\/help 1.9——在命令方块运行help会在上一个输出中出现一些有趣的东西 1.13——在命令方块运行help不再出现一些有趣的东西,也不再拆分成独立的页面 携带版alpha 0.16.0——加入了\/help 三. \/locate 作用:定位特殊的建筑(结构)。 需要权限等级:java-2,基岩-1 需要作弊:是 格式: java1.19版本前 \/locate <结构名> 基岩1.19.10版本前 \/locate <结构名>[仅在未生成的区块中查找:布尔值] 使用\/locate,可以在所在维度快速定位到最靠近命令执行地点的指定结构,比如村庄(vige)。在java版(1.13版本以及之后的版本),点击获取到的结构坐标还会在聊天框内自动生成tp指令。 其中,基岩版可以开启『仅在未生成的区块中查找』的功能,也就是仅仅在游戏地图尚未生成的地方查找结构,以避免『你找到了结构,却发现你之前已经来过了』这类事件发生。 注:该指令在java1.19版本和基岩1.19.10版本中迎来大更新,所以我们会在第六十七章重新讲解该指令(因为会涉及到一些新的知识)。 需要注意的是,返回的坐标并没有包含该结构的y轴,以及在java版中,结构名对大小写敏感。 结构名大全 java版: buried_treasure——埋藏的宝藏 endcity——末地城 fortress——下界要塞 mansion——林地府邸 mineshaft——废弃矿井 monument——海底遗迹 ocean_ruin——海底废墟 shipwreck——沉船 stronghold——要塞 desert_pyramid——沙漠神殿 igloo——雪屋 jungle_pyramid——丛林神庙 swamp_hut——女巫小屋(沼泽小屋) vige——村庄 piger_outpost——掠夺者前哨站 her_fossil——下界化石[该结构基岩版\/locate不支持寻找] bastion_remnant——堡垒遗迹 ruined_portal——废弃传送门 (注意,从java1.16开始结构名全部使用小写) 基岩版: buriedtreasure——埋藏的宝藏 endcity——末地城 fortress——下界要塞 mansion——林地府邸 mineshaft——废弃矿井 monument——海底遗迹 ruins——海底废墟 shipwreck——沉船 stronghold——要塞 temple——沙漠神殿、丛林神庙、沼泽小屋、雪屋(基岩版把这几个包含起来了,java1.13以下版本也是一样,只不过java1.13更新时拆了) vige——村庄 pigeroutpost——掠夺者前哨站 bastionremnant——堡垒遗迹 ruinedportal——废弃传送门 结构可以定位,但生物群系怎么定位? java1.16版本更新中,mojang就解决了这个问题——他们加入了\/locatebiome命令用于寻找生物群系。由于此指令加入得较晚,所以目前你需要到第六十七章学习(只不过现在又更新了......)。 历史 java 1.11——加入了\/locate,此时的locate是将沙漠神殿、丛林神庙、沼泽小屋、雪屋一同归类到temple中。 1.13——拆分了temple。同时,点击结构坐标可以生成传送指令了。 1.14——新增对piger_outpost(掠夺者前哨站)和new_vige(新村庄结构,此时的minecraft新村庄和老村庄结构都会生成)的支持。并在快照19w02a修复了mc-这个bug(玩家仍然能够使用\/locate寻找老村庄,因为老村庄结构在18w50a被删除,导致使用\/locate vige会出错),将new_vige改为vige替换原来的vige。 (没错,在快照18w48a和18w49a中,新村庄new_vige和旧村庄vige同时生成,这应该算是一个很冷门的知识了) 1.16——新增her_fossil(下界化石)的支持,并在随后的更新中将结构名全部小写。 1.18——结构id开始支持标签,并开始使用命名空间id 1.19——大更新 携带版和基岩版 1.0.0——加入又移除又加入了\/locate,并且只能用于寻找要塞 1.1.0——\/locate可以寻找其他结构了 1.17.30——加入了『仅在未生成的区块中查找』的功能 1.19.10——大更新 第二十二章 summon-生成实体 我们知道使用\/give可以获取物品,那么如何获取实体呢? 额,获取不了,倒是可以生成,这就需要\/summon指令。 \/summon,其单词summon中文译为“召唤”,所以\/summon指令的作用是:召唤一个实体。 \/summon 作用:召唤一个实体 需要权限等级:java-2,基岩-1 需要作弊:是 格式: java \/summon <召唤的实体>[<实体生成的位置:坐标>][实体数据标签:nbt] 基岩 \/summon <召唤的实体>[<实体生成的位置:坐标>][生成事件:字符串][实体名称:字符串] \/summon <召唤的实体><实体名称:字符串>[<实体生成的位置:坐标>] 召唤的实体可以是生物,也可以是一些载具,可以是弹射物,也可以是其他的一些实体。比如要召唤一只猪,你只需要: \/summon pig 但这召唤出来的是成年猪啊,我要的是幼年猪,我该怎么办? 在java版,这需要将nbt内age标签的值改为负数: \/summon minecraft:pig ~~~{age:-6000} 而在基岩版,你需要一个实体生成事件: \/summon pig ~~~ minecraft:entity_born 这样子可以生成出来一只小猪。 生成事件严格来说叫做生物事件,是基岩版独有的东西。生成事件用于自定义一个生物或实体其生成后的行为,且该生成事件是支持该实体的,不然无法生效。一个生成事件参数只能填写一个生成事件。关于生成事件基岩版有一个专门的指令:\/event。 由于生成事件比较难找(命令助手倒是有,就是为什么一定要用内置浏览器啊!),这儿就放几个比较常用的吧: minecraft:entity_spawned——实体自然生成:作用于可以自然生成的实体 minecraft:entity_born——生成幼年实体:作用于有幼年状态的生物(非亡灵生物) minecraft:ageable_grow_up——生成成年实体:作用于有成年状态的生物(非亡灵生物) minecraft:on_tame——生成已驯服实体:作用于可驯服的生物(狼:为什么我变成红色了?) minecraft:bee_angry——生成被激怒的实体:作用于中立生物和蠹虫,不包括北极熊 minecraft:bee_charged——生成具有闪电的实体:作用于苦力怕 minecraft:as_baby——生成幼年实体:作用于亡灵生物 minecraft:as_adult——生成成年实体:作用于亡灵生物 现在我们生成了一只小猪,但如果要生成一只倒立的小猪,那该怎么办? 正常情况下,你需要搞到命令牌并用铁砧将其重新命名为dinnerbone或grumm,然后给这只小猪赋予名字才行。 但如果要在服务器中自动化,这该怎么办? 在java版中,你只需要: \/summon minecraft:pig ~~~{age:-6000,customname:“{\\“text\\“:\\“dinnerbone\\“}“} 在基岩版更简单,你只需要: \/summon pig ~~~ minecraft:entity_born dinnerbone 看,一只倒立的小猪就出来了! 但大多数时候,我们并不需要一个倒立的小猪,我们只需要一只倒立的猪。在java版,只需要将age标签去掉即可,而在基岩版,我们就需要用到\/summon的第二种格式: \/summon pig dinnerbone ~~~ 这种格式去掉了生物事件,将自定义名称参数移到了坐标的前面。不愧是mojang,考虑得如此周到,不然我们还真的需要使用minecraft:entity_spawned生物事件了。 现在,你知道如何生成实体了吧? 历史: java 1.7.2——加入了\/summon 1.8——现在可以使用\/summon来生成闪电 1.16——现在可以使用\/summon来生成火球 携带版alpha 0.16.0——加入了\/summon 基岩版 ?——更改了\/summon的格式 第二十三章 setblock-放置方块 前面说过可以使用\/fill填充一个区域内的方块。但是如果只需要填充一个方块呢?那岂不是要把坐标输入两遍?minecraft给了我们一个简单的指令,可以放置一个方块,它就是:\/setblock。 \/setblock指令,是由set和block组成的。set前面讲过,是“设置”的意思,block就是方块的意思。 所以setblock的意思就是:设置方块,也就是放置方块。 \/setblock 作用:使用指定的方块替换一个方块 需要权限等级:java-2,基岩-1 需要作弊:是 格式: \/setblock <坐标><方块名>[方块数据值:int整数][被覆盖方块处理方式:destroy|keep|rece]——java1.13以下和基岩版 \/setblock <坐标><方块名>[方块状态][被覆盖方块处理方式:destroy|keep|rece]——java1.11至java1.12.2 \/setblock <坐标><方块名>[被覆盖方块处理方式:destroy|keep|rece]——java1.12.2以上 举个非常简单的例子。假设你需要在你自己脚下放置一个下界传送门方块,那么你只需要执行: \/setblock ~~-1 ~her_portal(java版) \/setblock ~~-1 ~ portal(基岩版) 然后你就进入了下界(我们需要再深入些)。 但如果我们在放置的时候同时也要让原本方块产生掉落物该怎么办? 很简单。举个例子,假设我们需要在脚底放置钻石块同时破坏掉原本的方块,就可以: \/setblock ~~-1 ~ diamond_block 0 destroy(java1.13版本以下和基岩版) \/setblock ~~-1 ~ diamond_block destroy(java1.12.2版本以上) 看,你脚底下的草方块变成了钻石块,还多出了个泥土! \/setblock的destroy处理方式和\/fill的destroy一样,都是会对原方块进行破坏并产生掉落物。 另外两个处理方式:keep和rece,我们都已经在\/fill指令见过了,那么它们是否也是和\/fill一样呢? rece肯定一样。但实际上又不完全一样——虽然\/setblock默认使用的处理方式也是rece,但是\/setblock的rece并没有“原方块是特定的方块才进行替换”的功能。 keep的作用和\/fill的keep不能说基本一样,只能说完全一样,只是因为\/setblock只替换一个方块,导致说法要改一下: 如果原方块是空气,即替换,否则不替换。 历史 java 1.7.2——加入了\/setblock。方块名参数支持数字和名称id。 1.8——方块名参数不再接受数字id。 1.11——加入了方块状态的支持。 携带版alpha 0.16.0——加入\/setblock 第二十四章 xp-控制经验值 经验值,在游戏中,一般有ex、exp和xp三种英文缩写,它的全称是:experience。经验值最早出现于rpg(角色扮演游戏)游戏的衡量角色能力的一种标准,每次经验值积累积达到上限时角色等级便会提升,并带来能力的相应提升。经验值作为最直接的经历评测标准已被广泛应用于诸多游戏中。 那么在minecraft中,经验值可以干啥?可以附魔,可以使用铁砧,仅此而已。 但是在基岩版,还没有记分板(scoreboard)的时候,经验值在服务器,那也是算一种货币的,也是一种像是记分板一样的存在的。 因为经验值就是一个变量。而我们这章所要知道的,就是如何去控制这个变量(经验值)。 minecraft有专门可以控制经验值的指令,它就是:\/xp。 \/xp 作用:给予单个或多个玩家经验值。 需要权限等级:java-2,基岩-1 需要作弊:是 格式: java1.13以下和基岩版 \/xp <数量:int整数>[玩家:目标选择器] java1.12.2以上版本 \/xp add <目标玩家:目标选择器><数量:int整数>[单位:levels|points] \/xp set <目标玩家:目标选择器><数量:int整数>[单位:levels|points] \/xp query <目标玩家:目标选择器>(单位:levels|points) 在基岩版和java1.13以下版本中,数量参数可以带单位,也可以不带单位。不带单位,就是增加经验点数。经验点数是啥?就是达到一定的程度就可以提升等级的那个绿色的小条条。如果带单位,单位只有“l”,也就是“等级”。比如下面两条指令: \/xp 33 \/xp 33l 前者指令只会让你获得33点经验值,后者会让你获得33级经验,差了不只是一个数量级(33点经验值能干啥?)。 (对,不填目标玩家默认是作用于命令执行者也就是你自己身上) 需要注意的是,经验点数无法减少(java1.13更新后除外),经验等级可以减少(填个负数)。 本来的这条指令很简单,直到java1.13更新,添加了一个新的指令: \/experience \/experience指令实际上就是\/xp的全称。由于该指令的添加,mojang也对这两条指令进行了重写,写成了像\/time指令一样有三个功能:add(增加)、set(设置)和query(查询) add(增加),也就是可以给目标玩家增加或减少特定的经验。比如: \/xp add @a 1 就是给全部玩家增加一点经验值(没错,不带单位默认还是经验值点数)。当然,是负数的话就会减少经验值,并且经验点数也可以减少了。 而原本的单位,被移到了最后面。举个例子: \/xp add @a 1 levels 这可以给全部玩家增加一级经验值。 set(设置)的话也是差不多个用法。比如: \/xp set @s 25 levels 就是设定自己的经验等级为25级 这里唯一要说的是query(查询)功能。 query一次只能查询一位玩家,也就是说,目标选择器选择@a之类的选择器会报错,不管你是否只有1名玩家。 如果你有仔细看上面的格式,你就会发现上面的格式出现了一个你从未见过的格式符号: (单位:levels|points) 这种用普通括号包裹起来的格式,一般指的是执行指令时必须填的参数,可以不填,但游戏没有给其安排默认值,导致不填不会报错,也不会有结果。 比如使用: \/xp query @s 就不会报错,也不会有结果 你就必须使用: \/xp query @s levels或是\/xp query @s points 才会有结果返回。 (这是特性,特性,懂不?) 好了,那么本章以及本卷就到此为止了! 历史 java 1.0.0——加入了\/xp。格式为\/xp <玩家:目标选择器><数量:int整数> 1.3.1——将玩家参数移到了后面,并且变更为可选参数。同时\/xp可以在单人游戏中使用了。 1.4.2——加入了l(level)单位,并且等级可以减少,点数无法减少。同时更改了\/xp数量参数上限从5000到int整形上限。 1.13——加入了\/experience成为了\/xp的全称,并重写了\/experience和\/xp指令,让点数和等级都支持负数值。 携带版alpha 0.16.0——加入了\/xp 第二十五章 更加精确的目标选择器 上 在java1.13及以上版本或基岩版中,当你在输入目标选择器之后,指令提示往往会出现一个符号,这个符号就是『[』。 为什么呢?其实,一个目标选择器实际上有两个部分: <变量>[筛选参数] 其中的变量即我们了解过的@a、@e之类的,而筛选参数则是通过各种特定的条件从已选择的实体中细分出需要的实体。 那么到底有多少种筛选参数呢?答:到目前为止(2022-8-3),java版有21个筛选参数,基岩版有22个筛选参数。 这些参数如下: --坐标-- \\\\坐标\\\\ x、y、z \\\\距离(球形范围)\\\\ distance(je1.13及以上) r、rm(be和je1.13以下) \\\\立方体范围\\\\ dx、dy、dz --旋转角度-- \\\\垂直旋转角度\\\\ x_rotation(je1.13及以上) rx、rxm(be和je1.13以下) \\\\水平旋转角度\\\\ y_rotation(je1.13及以上) ry、rym(be和je1.13以下) --记分板-- \\\\记分板分数\\\\ scores(je1.13及以上和be) score(je1.13以下) \\\\标签\\\\ tag \\\\队伍名\\\\(仅java) team --其他-- \\\\数量\\\\ limit、sort(je1.13及以上) c(be和je1.13以下) \\\\经验等级\\\\ level(je1.13及以上) l、lm(be和je1.13以下) \\\\游戏模式\\\\ gamemode(je1.13及以上) m(be和je1.13以下) \\\\名称\\\\ name \\\\实体类型\\\\ type \\\\实体家族\\\\(仅基岩版) family \\\\物品\\\\ hasitem \\\\实体数据标签\\\\(仅java版) nbt \\\\游戏进度\\\\(仅java版) advancements \\\\谓词\\\\(仅java版) predicate 看起来好像很复杂的样子?部分参数的确有点复杂,但大部分还是很简单的。 我们先看看格式: (注意,接下来的“[]”都不属于格式的符号,属于必填符号,“<>”符号仍是格式符号) [<参数名>=<参数值>,<参数名>=<参数值>,…] 唉,你有没有发现,这和json的格式有点像啊。 没错,和json一样,目标选择器的每个参数也是一个『键-值对』。只不过需要注意以下三点: 1目标选择器参数部分的最外层必须要用中括号包起来 2目标选择器的每个参数,其参数名和参数值之间是用等于号分开,而不是用分号 3平台特性,大部分英文半角符号会被强制改为中文全角符号 现在详细的讲讲各种参数的使用方式。 ——坐标—— 这个很熟悉吧,就是坐标而已。“x”就是x坐标,“y”就是y坐标,“z”就是z坐标。 那么举个栗子: @e[x=1,y=60,z=30] 这个意思是设定基准点为(1,60,30)。什么是基准点呢?我们在第七章中了解到指令具有三要素:指令执行者、指令执行的地点和参数。 其中,指令执行的地点也可以叫做指令执行的基准点,简称执行点。 所以说? 你是不是以为这三个用于确定位置的参数就是用来确定这个『指令执行的基准点』?当然不是确定这个基准点啦。实际上,除了这个基准点外,目标选择器中还有一个特殊的基准点。这个基准点只有一个用处:用于给目标选择器中的某些参数提供中心。而这个基准点,就是通过x、y、z三个参数确定的(如果没有用这三个参数确定,那么默认是采用指令执行的地点)。 那么到底是哪些参数需要用到这个基准点呢?接下来你就知道了。 对了,在基岩版,x、y、z三个参数的值是可以使用相对坐标的。比如: @e[x=~1,y=~,z=~] 这将会设定基准点在指令执行位置往东一格的地方。 ——距离—— 使用圆规画圆,首先需要找到一个圆心,然后确定圆的半径,最后旋转360°就画出了一个圆。 在minecraft中,使用距离参数确定选择实体的范围,本质上就是在画一个圆(实际上是个球)。这个圆的圆心就是上面那三个参数确定的基准点,圆的半径则是需要使用r或是distance参数确定。 比如: @a[x=23,y=65,z=-33,r=10]——java1.13以下和基岩版 @a[x=23,y=65,z=-33,distance=..10]——java1.13及以上 这个目标选择器的意思是:以坐标(23,65,-33)为基准点,范围10格内的所有玩家 但如果我们要这范围10格以外的玩家怎么办?这样做: @a[x=23,y=65,z=-33,rm=10]——java1.13以下和基岩版 @a[x=23,y=65,z=-33,distance=10..]——java1.13及以上 这个目标选择器的意思是:以坐标(23,65,-33)为基准点,范围10格外的所有玩家 可惜起点并不能放图,不然这用图表示会更好。 我们可以总结出r和rm的作用: r参数的作用是:选取所有距离基准点小于r格的实体 rm参数的作用是:选取所有距离基准点大于rm格的实体 更高级一点,你还可以r和rm一起用,比如: @a[x=23,y=65,z=-33,r=10,rm=5]——java1.13以下和基岩版 @a[x=23,y=65,z=-33,distance=5..10]——java1.13及以上 这样子可以选取距离基准点大于5格但小于10格的玩家(相当于画两个圆组成一个圆环,然后选取圆环内部及边缘的实体)。 你也可以: @a[x=23,y=65,z=-33,r=10,rm=10]——java1.13以下和基岩版 @a[x=23,y=65,z=-33,distance=10]——java1.13及以上 这样子可以选取距离基准点10格的玩家(注意,只能是10格,多一点少一点都不行)。 需要注意的是,r必须大于等于rm,不然什么也选不中。 r和rm毕竟是基岩版和java1.13以下版本用的,在java版1.13及以上版本使用的distance,又是怎么用的呢? 其实上面讲r和rm时,顺带列出来相同用法的distance,就已经告诉你distance的四种用法了。 如果你还不清楚,我们就将r和rm两个参数值代入到distance,来告诉你distance到底怎么用: [distance =..r]——选取所有距离基准点小于r格的实体 [distance =rm..]——选取所有距离基准点大于rm格的实体。 [distance =rm..r]——选取所有距离基准点大于rm格小于r格的实体。 [distance =r|rm]——选取所有距离基准点rm(r)格的实体。 发现规律了没有?那两个点在数字左边,就代表小于x格的实体;在右边,即大于x格的实体;在两个数值中间,就代表距离在这两个值中间的实体;没有那两个点,只有一个数值,那么就只代表距离x格的实体。 (立方体范围) 使用\/fill确定的立方体范围很好理解,而目标选择器的立方体范围...... 因为它并不是让你找两个点...... 而是,以基准点分别向三个方向延伸多少格构成的立方体! (mojang本来这么做是为了相对坐标,只不过这就导致使用绝对坐标时很头疼) 举个最简单的例子: @a [x=0,y=0,z=0,dx=10,dy=10,dz=10] 这个目标选择器的意思是: 选取从(0,0,0)到(10,10,10)构成的立方体内的所有玩家。 更深一层的意思是: 以基准点(0,0,0)向正x轴延伸10格,正y轴延伸10格,正z轴延伸10格所构成的立方体内的所有玩家。 但一般来说,基准点可不会是这么简单的三个数值。所以我们使用dx、dy、dz时,必须要掌握一个技术:将\/fill构成立方体的两点坐标转化为目标选择器的基准点和延伸格数。 将\/fill构成立方体的两个坐标记为: a?=(x?,y?,z?) a?=(x?,y?,z?) 设定a?为基准点,即: [x=x?,y=y?,z=z?] a?-a?,得: a?=(x?-x?,y?-y?,z?-z?) 这个结果就是dx、dy、dz的值了: [x=x?,y=y?,z=z?,dx=x?-x?,dy=y?-y?,dz=z?-z?] 举个例子: a?=(287,65,122) a?=(300,69,24) 就可以得出: [x=287,y=65,z=122,dx=13,dy=4,dz=-98] 这样子,以后我们就不用刻意去记到底要延伸多少格了(除了x、y、z并没有指定的情况下,这时候就要以相对坐标的思维去思考了)。 对了,在java版,判定实体是否在范围内是按照碰撞箱是否有重叠判断,在基岩版则是按照脚部坐标判断。 ——记分板分数—— ——记分板标签—— ——队伍名称—— 上面几格都是关于“记分板”(scoreboard)的,这个会在第四十九章中讲到。 ——数量—— 这个很有意思。java1.13及以上版本是limit和sort,基岩版和java1.13以下版本是只有一个c。 由于limit和sort相比于c是大径相庭,所以我们先从limit和sort开始。 使用@e,我们可以选择所有实体,但我们该怎么选择10只实体呢? @e[limit=10] 就可以了。 但如果要选中最靠近目标选择器基准点的实体该怎么办? 这时候我们就需要使用sort,调整选取模式。 在java1.13及以上版本中,@a和@e这两个目标选择器变量的默认选取模式是按照实体生成时间由长到短排列,即越老排越前面,对应sort的选取模式即:arbitrary。 我们要选中最靠近基准点的实体,只需要使用nearest模式即可: @e[limit=1,sort=nearest] 这样子就可以选取最靠近基准点的实体。但请注意,在基岩版和java1.13以下版本中,@a和@e这两个目标选择器变量是按照实体与目标选择器基准点的距离从小到大排列的,也就是nearest模式,并不是按照实体生成时间排列。 sort一共有四种模式: nearest——由近到远 furthest——由远到近 random——随机 arbitrary——按生成时间由老到新 其中,对于arbitrary模式来讲,『c』这个参数基本上无法模仿。 那么c参数该如何使用呢? 先别着急,因为还有一个知识点没讲: 其实,当使用@p和@r变量时,limit或c默认为1,更改limit或c会增加选择最近(@p默认排列模式为nearest)或随机(@r默认为random模式)目标的数量。当使用@a或@e变量时,此方式会限制目标数量。如果是@s呢?那还用说吗?你有10个吗?minecraft可没有分身术。 注意一点,limit不能写负数,但c可以。 c参数为正整数时,在除@r变量外会选取最靠近基准点的c个目标;为负整数时,在除@r变量外会选取最远离基准点的c个目标。比如: @a[c=5] @a[c=-5] 前者会选取最近的5名玩家,后者会选取最远的5名玩家。 但如果要随机排序呢?那么就得用@r(随机排序)变量了。 c参数还有一个小知识,如果所有目标都一样远(你这不是钻牛角尖吗),在负整数的情况下将会选取生成时间越晚的实体,正整数情况下将会选取生成时间越早的实体。 ——经验等级—— 这个用来选取经验等级的参数,两个版本又不相同了。java1.13及以上版本是level,基岩版和低于java1.13的版本是l和lm。 等等,你有没有发现,这和那个rm、r、distance不超级像的吗? 没错,基本上你怎么用距离的,选取经验等级就怎么用。比如选取经验等级小于等于5的玩家: @a[l=5]——java1.13以下和基岩版 @a[level=..5]——java1.13及以上 又比如选取经验等级大于等于5的玩家: @a[lm=5]——java1.13以下和基岩版 @a[level=5..]——java1.13及以上 又比如选取经验等级在5到10级之间(含5和10级)的玩家: @a[l=10,lm=5]——java1.13以下和基岩版 @a[level=5..10]——java1.13及以上 又比如选取经验等级正正好好为5级的玩家: @a[l=5,lm=5]——java1.13以下和基岩版 @a[level=5]——java1.13及以上 懂了吧?不懂就对照r、rm、distance多看几遍。 本章就到此结束。 第二十六章 更加精确的目标选择器 下 ——游戏模式—— 用游戏模式筛选玩家的参数,在java1.13及以上版本中是gamemode,在基岩版以及低于java1.13的版本均为m。 那么它们是怎么用的呢? 众所周知,基岩版服务器并没有像java版服务器一样具有出生点保护,所以在基岩版,要让服务器主城不被恶意破坏,最基本的操作就是使用『范围冒险模式』。比如这个中国版租贷服最初就用了如下指令: \/gamemode a @a[x=726,y=89,z=-263,r=50] 重复执行这条指令,就可以让主城范围50格内的所有玩家都改为冒险模式。但这有个缺点:腐竹也被改为冒险模式了。为了解决这个问题,这个腐竹给该目标选择器添加了一个参数,变成: \/gamemode a @a[x=726,y=89,z=-263,r=50,m=s] 这条指令和上一条指令的唯一区别就在于,它不会将不是生存模式的玩家改为冒险模式,这样子腐竹开着创造就不会受到影响了。其中新添加的m参数,值是s,也就是survival(生存)的缩写。 m参数可以使用游戏模式的全称,缩写和数字id。比如: \/tp @a[r=20,m=6]^^^-100(仅适用于基岩版) 这条指令的作用是:将以基准点(在这是指令执行位置)为中心,半径20格内的所有处于旁观模式的玩家,全都传送到执行者背后100米处(^^^-100为局部坐标,会在第五十九章讲到。『6』在这是基岩版1.19及以上版本为实验玩法的旁观者模式的数字id。没错,基岩版也有旁观者模式了,只不过在测试而已) 而gamemode参数.......在java1.13版本中,mojang重写了大量游戏基础代码,导致java1.12.2和1.13版本中,许多游戏内容差异极大。所以在之前的章节中,你会发现许多指令都在java1.13更新中发生了大改,这种情况在以后的章节中也会持续存在。游戏模式也一样,在java1.13版本更新后,游戏模式就仅支持全称,即: survival(生存模式)、creative(创造模式)、adventure(冒险模式)和spectator(旁观模式)。 所以,虽然gamemode参数和m用法一样,但它仅支持上面四个值。 现在我们知道如何选择特定游戏模式的玩家。但如果我们要反过来,排除特定模式的玩家该怎么办? 这位腐竹造了一个房子。为了防止他的房子被破坏,就做了一个简易的安保措施: \/kill @a[r=15,m=!c] 这条指令的意思是:将范围15格内所有不处于创造模式的玩家全部杀死。 仔细观察这条指令,你发现了什么? 没错,m参数要反过来排除特定模式的玩家,只需要在值前面加一个英文半角感叹号。和m参数一样,gamemode参数也同理: \/kill @a[distance=..15,gamemode=!creative] 感叹号的这种用法,其实就是不等号在计算机语言中的常见形式(=!)。这种不等号反转选择的用法在接下来几个目标选择器参数中也会频繁出现。 ——目标名称—— name参数可以用于选取指定名称的实体。 使用\/give给予某位特定玩家物品时,一般不会用到目标选择器,而是直接指定该玩家的玩家名(不会吧,不会吧,不会真的有人会用玩家的uuid来使用\/give指令吧)。 但如果要用目标选择器,还要锁定这名玩家该怎么办? 举个例子: \/give @a[name=jie灬挥刀乱砍] skyward_de 这样子就可以锁定这名玩家并给予物品了。 name参数不光可以用于玩家名上,还可以用于实体名上。 比如某位java腐竹为了实现将宝箱随机放在世界各处,用了如下指令: \/summon minecraft:armor_stand ~~~{customname:“\\“a\\““} \\\\召唤一个名为a的盔甲架\\\\ \/spreadyers ~~ 32 false @e[type=minecraft:armor_stand,name=a] \\\\将所有名为a的盔甲架随机传送到以该命令方块为中心的x范围内,且每个盔甲架间距不小于32格,不考虑盔甲架的队伍属性\\\\ \/execute as @e[type=minecraft:armor_stand,name=a] at @s run ......(后面省略) \\\\将执行者、执行位置和旋转角度都设定为名为a的盔甲架,并运行.....\\\\ 可以发现,该腐竹为了防止执行指令时和其他实体发生冲突,特别使用了名叫a的盔甲架并用name参数锁定。同时,这位腐竹还用到了type参数。关于这个参数待会会讲到。 name参数也可以像m、gamemode参数一样,使用感叹号反转为排除指定名称的实体,比如: \/kill @e[name=!a] 这条指令的作用就是:杀死名字不是a的实体。 需要注意一点,如果名字中包含空格,需要用双引号括起。比如: \/kill @e[name=“genshin impact“] ——垂直旋转角度—— ——水平旋转角度—— 还记得第九章的\/tp吗?我们就在那第一次接触到了垂直旋转角度和水平旋转角度: 这两个由于是同类,本书就合起来讲了。 在java1.13及以上版本中,垂直旋转角度参数是x_rotation,水平旋转角度参数是y_rotation。在java1.13以下和基岩版中,两类角度分别是rx、rxm和ry、rym。 唉,你发现了没有?这和我们之前了解过的经验参数(l、lm和level)还有距离参数(r、rm和distance)差不多。那么格式是不是也是一样呢? 还真是一样的。既然格式一样,这里就不多说它的格式了。 rx、ry参数的作用是:选取垂直、水平旋转角度小于等于rx或ry的实体 rxm、rym参数的作用是:选取垂直、水平旋转角度大于等于rxm或rym的实体 垂直旋转角度其范围是:90度(看地上)到-90度(看天空)。 水平旋转角度其范围是:-180度(北)到180度(还是北),或者说是上北-180°,下南0°。左西90°,右东-90°。 等等,我们在讲tp时,不是说水平旋转角度是:『以实体为中心,以正南(z轴正方向)为0°,顺时针下来,实体朝向和正南方向的夹角(也或者说实体在真南方位角体系中朝向的角度),就是该实体的水平旋转角度。』 那这怎么跑出来负数了? 其实在minecraft中,水平旋转角度虽然可以像我们之前在第九章讲tp时那么用,但大多数时候,你都得这么用: 以正南(z轴正方向)为0°,顺时针旋转180°通过正西至正北,用正数,逆时针旋转180°通过正东至正北,用负数。比如-45°,就代表以正南为基准,逆时针旋转45°的方向;30°,就代表以正南为基准,顺时针旋转30°的方向。 也就是说,在minecraft中,水平旋转角度的正确范围是-180°~180°,而不是0°~360°。至于为什么我要在第九章那么讲,只是怕一下子就把负数搬出来会吓你们一跳。 现在我们回到正题。 举个例子。某网易手机租贷服为了让玩家回城方便,搞了一个“回城雪球”,其指令如下: a→b→c→ a:重复,无条件,始终活动 \/execute @e[type=snowball]~~~ execute @p[r=1.5,rx=90,rxm=60]~~~ execute @e[type=snowball,c=1]~~~ tag @s add back_home \\\\选取雪球作为指令执行者,再以这个雪球为中心寻找半径1.5格内最近的低着头(头自水平线向下90°到向下60°)的玩家。如果找到,再以该玩家为中心寻找最靠近他的雪球,并给这个雪球赋予back_home标签。\\\\ b:连锁,有条件的,始终活动 \/execute @e[type=snowball,tag=back_home]~~~ tp @p[r=1.5] 323 65 72 \\\\选取具有back_home标签的雪球,并以它为中心将半径1.5格内最靠近它的玩家传送到(323,65,72)。\\\\ c:连锁,有条件的,始终活动 \/kill @e[type=snowball,tag=back_home] \\\\清除所有具有back_home标签的雪球\\\\ 其中就有用到rx和rxm参数,用于筛选那些低着头扔雪球的玩家。 至于其中出现的tag参数,我们在上一章已经略过了。关于tag会在以后讲到计分板时提到。 ry和rym参数目前来说没有特别广的用途,只能举个没啥用的例子: \/kill @a[ry=180,rym=-180] 这条指令可以杀死所有面向正北的玩家(神奇的是这并不会框选住所有活着的玩家,@a[ry=180,rym=179]才会框选住几乎所有活着的玩家) 至于x_rotation和y_rotation参数,你应该知道怎么用了吧? @a[x_rotation=35..]——所有头水平线朝下35°及以上的玩家 @a[x_rotation=..35]——所有头没有水平线朝下35°以上的玩家 @a[x_rotation=0..35]——所有头水平线朝下0到35°(含)的玩家 @a[x_rotation=35]——所有头水平线朝下35°的玩家 @a[y_rotation =60..]——所有朝向是在南偏西60°顺时针到正北这个范围内的玩家 @a[y_rotation =..60]——所有朝向是在南偏西60°逆时针到正北这个范围内的玩家 @a[y_rotation =60..120]——所有朝向是在南偏西60°顺时针到北偏西60°这个范围内的玩家 @a[y_rotation =60]——所有朝着南偏西60°的玩家 ——实体类型—— 实体类型是type,上面我们已经见过了。 type和name本质上是差不多的,但是它筛选不是通过名字,而是通过实体种类。 什么是实体种类?比如一个玩家叫notch,另一个玩家叫herobrine,虽然名字不同,但他们都是『玩家』种类的。又比如这里有一只马,那里有一只叫马的驴,虽然它们都叫马,但前者是马,后者是驴,并不是一个种类的。 type可以选定指定类型的实体,比如: \/kill @e[type=minecraft:viger] 就可以杀死全部已生成的村民。 type一般来说仅用于@e,因为只有@e是包含非玩家实体的。在java1.13以下和基岩版中,你也可以用在@r中来随机选择特定类型的实体。 和name一样,type也支持感叹号反转: \/kill @e[type=!yer] 这条指令的作用是:杀死所有非玩家实体。 需要注意的是,name和type这两个参数在非感叹号反转的情况下都是不可重叠的,比如: @e[type=cow,type=yer] 像上面那样是不可以的,minecraft中可没有既是牛又是玩家的动物。如果真有,那么也应该合并成为一个新的实体,也许会叫作cow_yer(牛人)呢。 ——实体家族—— 我们知道通过type可以选取特定类型的实体。但如果我们要选取一堆不同类型的实体用于执行同一种指令呢? 记分板、nbt和标签可以很好的解决这个问题。但在了解这三个东西之前,我们暂且没有除多弄命令方块以外的更好的办法。 mojang估计看我们这么可怜,于是在基岩版1.16.100中,加入了family参数。 family参数和type参数差不多,只不过它是通过实体家族筛选的。 什么是实体家族? 举个例子: 僵尸知道吧?僵尸一般来说有三类变种: 尸壳、僵尸村民、溺尸 虽然它们客观上并不属于同一种实体,但主观上我们仍然会将它们归类到一个大类:僵尸类。 用mojang的说法,它们都是属于同一个族(family)的。 现在你应该知道实体家族到底是什么了吧? 举个例子: \/tp @e[family=creeper]@s 这条指令的作用是:将所有属于苦力怕家族的实体传送到自己身旁。 当然,你也可以使用感叹号将作用反转。需要注意,和type、name参数不同的是,family参数在非反转情况下也是可以叠加使用的,因为有些实体可能会属于多个族。 你可以在minecraft wiki上搜索『族』词条来查看原版所有可用的实体家族。 ——物品—— 我们知道,在java版中,如果要筛选具有指定物品的实体,可以使用nbt或\/clear。那在基岩版中该怎么办?使用\/receitem或\/clear吗? 这的确是两种可行的方法,但mojang还给了我们第三个方法: hasitem目标选择器参数 这个参数可能会比较复杂,因此在了解这个参数之前,我们得先了解一下:背包中的物品 背包具有很多个物品栏,每个物品栏具有多个栏位,栏位储存着物品。因此,每个放在背包中的物品都具有栏位标签。物品有很多个种类,因此,物品还具有id标签。大部分类型的物品可以堆叠,因此,物品还具有数量标签。在java1.13以下版本和基岩版中,同id的物品也可能不同,因此,物品在这些版本中还具有数据值标签。 hasitem参数可以用来选取具有指定物品的实体。更准确一点来说,hasitem参数可以通过检测已选实体的背包中指定条件下的物品,来筛选实体。 hasitem参数的值比较特别,它的值可以是单个条件,也可以是由多个条件组成的条件列表。让我们来看看hasitem参数的一个条件项目到底可以指定哪些东西。 一个条件项目可以检测单个类型的物品,具体来说可以指定以下的参数: item——物品id data——物品的数据值[可选] quantity——限制所选范围内物品的总数量[可选] location——需要检测的物品栏[可选] slot——需要检测的槽位[可选,必须配合location参数使用] 比如: {item=bed,data=1} 这个条件可以筛选背包内具有橙色床的实体。不难发现,单个条件可以具有多个不同的筛选参数,并且外面要使用花括号({})包裹起来。 需要注意的是,data参数目前有个bug,就是不能适用于方块类物品。如果你对一个方块类物品使用了data参数,那么不管你怎么改data的值,游戏总会认为该参数的值为0。怎么判断一个物品是不是方块类的呢?看物品的图标。如果图标是直接给出了方块的3d图像(也就是渲染图),比如羊毛,那就是方块类物品。像是床这种图标是专门画的就不是方块类物品,所以能够正常使用data参数。 quantity参数得好好讲一讲,它并不是说检测单个栏位内物品的数量,而是检测整个范围内的指定类型物品数量总和。比如: {item=dirt,quantity=100..} 这个条件可以选择到那些背包内泥土数量达到甚至超过100块的实体。也就是说,假设这里有一个张三,背包内有两组泥土,那么这个条件就可以选择到它。 不难发现,quantity的值简直是基岩版的一股清流,竟然向java1.13及以上的版本学习,采用了java版先进的『两点法』,不错不错,值得表扬。而且,这参数还在java版的基础上改造了一下,变成了还可以使用不等号进行反选: {item=dirt,quantity=!100..} 这将会选取拥有泥土数量<100的实体。 对了,如果你指定了这个参数为0,那就可以选择『没有指定物品的实体』: {item=dirt,quantity=0} 这将会选取背包内没有泥土的实体。 location参数可以缩小检测的范围到指定的物品栏。具体可以使用哪些物品栏以及这里的物品栏是个啥东西.....这就需要你前往第三十八章了解\/receitem指令。 这里就先假装你已经搞懂了这些内容。举个例子: {item=dirt,quantity=0,location=slot.enderchest} 这将会选取所有在其末影箱内没有泥土的实体。需要注意,对于玩家来说,默认是不会检测到末影箱的。也就是说,如果你在末影箱内放了一块泥土,那么{item=dirt,quantity=0}这个条件还是会选择到你,但{item=dirt,quantity=0,location=slot.enderchest}这个条件则不会。另外,即使是对于没有末影箱的非玩家实体,游戏仍然会假装其具有末影箱,然后又因为游戏假装出来的末影箱内没有泥土,导致上述条件也会选择到非玩家实体。 在使用location参数时,还可以更进一步使用slot参数来缩小检测范围到指定的栏位。比如: {item=dirt,quantity=1..,location=slot.enderchest,slot=0} 这将会选取到所有在其末影箱左上角第一格内放有泥土的玩家。和quantity一样,这参数同样也支持升级后的『两点法』: {item=dirt,quantity=1..,location=slot.enderchest,slot=1..} \\\\选取到所有在其末影箱内除了左上角第一格外其他位置放有泥土的玩家\\\\ {item=dirt,quantity=1..,location=slot.enderchest,slot=!0} \\\\同上\\\\ 上面这些都是一个条件内可以弄的参数,hasitem参数的值也确实可以直接放入单个条件: \/testfor @a[hasitem={item=dirt,quantity=1..,location=slot.enderchest,slot=!0}] 但是如果要多个条件呢?这时候就需要用到列表: @a[hasitem=[{item=dirt},{item=apple}]] 这将会选择到背包内同时具有泥土和苹果的玩家。 不难发现,在多个条件组成的列表中,每个条件也是使用逗号分开,列表最外侧被中括号([])包起来。 这就是hasitem参数的具体使用方法,其中部分内容超纲了一些,但总体上还是易于理解的。 ——nbt—— ——进度—— ——谓词—— 上面这三个均为java版独有,且我们还未接触到,暂时先留个坑,以后再填。 附录:目标选择器发展历史 java 1.4.2——加入目标选择器,最初只有@a、@r、@p三个变量 1.8——加入了@e变量和dx、dy、dz参数 1.9——m参数现在接受游戏模式全称和缩写,在此版本之前只支持数字id。并加入了tag参数。 1.11——移除了隐含目标选择器(如@a[26,65,-28],代表@a[x=26,y=65,z=-28]),并且错误的目标选择器不再略过,而是会报错。 1.12——加入了@s变量 1.13——加入了nbt和进度advancements参数,并对原本的参数进行大改 1.15——加入了谓词predicate 基岩版 1.16.100——加入了family参数 1.17.10——加入@initiator变量用于npc 1.18.30——加入了hasitem参数 (注:网易版我的世界截止目前[2022.8.3]仅仅更新到1.18.10版本,因此没有hasitem参数) 第二十七章 游戏刻 在之前,我们曾提到过“游戏刻”,它的速度是20游戏刻(t)=1秒。 然而,其实minecraft中有三种刻,游戏刻只是其中的一种。 还有两种分别是:区块刻和红石刻。(当然我们暂时用不到那么高深的内容) 先说说游戏刻。游戏刻正常来说每秒能运行20次,即20游戏刻=1秒。 但是其实游戏刻的速度也不是完全固定的。如果你的电脑很渣(比如windows xp),或者是你的手机处理器很差,不足以跟上这个速度,游戏刻就会变慢。因为minecraft内许多事情都是依靠游戏刻而不是现实中的秒运算的(就比如命令方块),这就会导致整个minecraft运行变慢。 游戏刻的速度和fps有多高并没有多大关系,fps是由显卡决定,而游戏刻是由cpu决定,除非你的游戏界面是用cpu硬算出来的,不然两者没多大关系。 游戏刻的速度一般用每秒游戏刻数(tps,ticks per second,刻\/每秒)或每刻毫秒数(mspt,milliseconds per tick,毫秒\/刻)。每秒游戏刻数越高越好,正常情况下是能达到20tps;每刻毫秒数越低越好,这代表你的电脑处理每一游戏刻有多快。 tps和mspt经常出现在服务器中,当然最常见的还是前者tps。现在你已经了解了游戏刻,知道了tps和mspt是什么意思,以后玩服务器的时候相信疑惑的次数就会更少一点了吧。 第二十八章 区块与区段 在上一章中,我们提到了“区块刻”。区块刻是个啥我们暂时不用了解,但区块我们还是要很详细的了解一下。 首先让我们认识一下区块(chunk)。 当你在minecraft世界行走时,你或许会发现你的视野边缘是由一个个正方形的区域组成的。这些正方形区域就是正在加载的区块。 minecraft的世界是由一个个区块组成的,每个区块的长宽是16格,高是256格。在还未正式发布的minecraft1.18版本中,区块的高度甚至达到了384格。 所以说,一个区块包含着块方块。而一个世界最多可以生成个区块(约为14亿),每种区块都有7.46x10(的244,700次方)种可能的区块种类。怎么样,是不是很震撼?照这样计算,一个世界就有(921.6京[1京=万亿])块方块。 但是上面这些只是真区块。什么是真区块呢?听说过minecraft的边境之地吧,当你到达minecraft的很远的地方时,那里的区块会出现bug,也就是加载错误(32位溢出)。在java版中,这个bug早就已经在beta1.8版本移除(但没有完全移除,64位溢出导致的边境之地仍然存在),并添加了世界边界拦着你。当你以任何方式越过世界边界后来到外面,会得到一些负面效果,扣血死亡,就好像绝地求生里一样。其实java版的minecraft还真的有点像绝地求生,你还可以使用特定的指令修改边界,来达到绝地求生的效果。是不是很神奇? 在基岩版,并没有边界,所以你仍然可以看到那个神奇的区块。但可惜,基岩版的边境之地即将于1.17.2版本移除,目前的1.17.2测试版中边境之地已经木掉了。 所以,真区块就是正常没有bug的区块。而那些bug的区块,则被叫做“假区块”。 一个区块被分成数个长宽高均为16格的区段。实际上,虽然区块这个词更常见,但是在minecraft中,大多数游戏的运算都是以区段而不是以区块为单位的。 随机刻就是一个很好的例子。区块刻运算过程中,有一个刻叫随机刻。随机刻我们在讲\/gamerule指令时已经见过了,但是我们还不知道它的运作方式。 那么它是怎么运作的呢? 一个区段有16x16x16=4096个方块。每一随机刻中,将会随机抽取randomtickspeed规则设定的数量的方块,即默认java是抽取3个方块,基岩是抽取1个方块。 大多数方块被抽到后并不会有什么影响,但以下方块会收到影响: 耕地上的农作物——有水可能生长,无水可能掉落 蘑菇——光照低则有可能传播,光照高则有可能掉落 藤蔓(wàn)——可能传播 火[仅基岩版]——可能熄灭或传播 冰和雪——可能融化 树叶——在附近没有树干的情况下可能枯萎 耕地——湿润程度会更新 可以生长的植物和滴水石锥——可能生长 草方块和菌丝——可能传播或变为泥土 树苗——可能长成树 岩浆——可能让附近的方块上着火 红石矿石——会熄灭 下界传送门方块——可能生成一只猪灵(minecraft1.16版本及以上)或僵尸猪人(低于minecraft1.16) 海龟蛋——破裂或孵化 营火——会冒出烟雾粒子 铜质方块——可能生锈 处于滴水石锥下方的炼药锅——如果滴水石锥上方有熔岩或水,炼药锅可能会被填充 一个minecraft存档包含超级多的区块,所以游戏游玩时肯定不会将这些区块全部加载,而是选取部分区块进行加载。 在java版,每个区块要加载都需要一个加载标签。每个加载标签都具有三个属性: 加载等级、标签类型和存活时间(可选属性) 加载等级,即规定了该区块的加载级别有多高。加载等级越小,能加载的内容就越多。如果加载等级有多个,那么将会生效的将会是数值最小的那个。 加载等级的范围是22到44,分为四个类型: 强加载:≤31——所有游戏内容都会运算 弱加载:32——除区块刻、实体以外其他游戏内容都会运算 加载边界:33——只有少部分内容会正常运行(红石、命令方块不会运行) 不可访问:34——只有世界生成会在这些区块中运行 加载等级会向相邻8个区块传播,每成功传播一次加载等级会加一级。 标签类型,用于确定该加载标签的来源。目前来说,标签类型有以下几种来源: \\\\玩家\\\\ 加载范围:正方形,边长为渲染距离(单人)或view-distance(多人)x2+1 加载等级:31 比如,当渲染距离为12时,游戏就会加载以玩家为中心的25x25个强加载区块,外边围着一圈弱加载区块和加载边界。 \\\\强制\\\\ 使用\/forceload指令赋予 等级:31 \\\\出生点\\\\ 等级:22 强加载范围:19x19 \\\\传送门\\\\ 使用下界传送门时,游戏会给予即将到达的另一个维度区块赋予等级30的加载标签。 强加载范围:3x3 \\\\末影龙\\\\ 等级:24 强加载范围:15x15 \\\\瞬移\\\\ 实体(注意不是玩家)瞬移后(包括使用\/tp、\/spreadyers和末地传送门,刷沙机就是利用了这个原理)在瞬移后的区块创建的为时5游戏刻的加载标签。 等级:33(使用\/tp是32) \\\\临时\\\\ 其他游戏代码告诉游戏该区块需要加载时临时建立的标签,仅持续1游戏刻。 等级:至少为33,视游戏代码而定。 在基岩版,玩家加载的范围和java版不一样,呈现一个圆形。使用\/tickingarea,也可以像\/forceload一样一直让区块保持加载。 现在,你知道了区块是个什么东西了吧? (唉,你看,这个矿洞会生成史莱姆唉!) 第二十九章 更深入地了解指令参数 在序言中,我们提到了一条指令由一个指令名+许多指令参数组成。 在学习过程中,你可能已经发现了,许多指令中经常出现以下参数: 实体id 方块id 物品id 值:int整形 ....... 上面这些参数中,前三者被统一叫做id参数(命名空间id参数)。id参数实际上不止这三个,还有药水效果id(\/effect指令)、魔咒id(\/enchant),但由于这三个最常见,所以这儿就拿它们三研究。 id参数都有一个特点:都具有命名空间 什么是命名空间?举个例子,原版钻石id名是diamond,但在游戏里这个钻石id名是: minecraft:diamond 前面的『minecraft:』就是这个id的命名空间。 命名空间有什么用?还是以钻石举例,假设此时有一个模组,其中也有一个id是diamond的“金刚石”。如果没有命名空间,那么这个模组就会与原版游戏发生冲突。而有命名空间的情况下,这个问题就得到了解决,因为这个模组的“金刚石”,在模组中其id实际上是: mining_industry:diamond 关于命名空间更深入的研究以后再来,现在让我们来看看id参数普遍的格式: [命名空间]: 需要注意的是,部分id参数命名空间是必填的,如基岩版\/summon的生物事件参数。大部分id参数命名空间是默认为『minecraft:』。 大部分id参数都是这个格式,但也有少数id参数在java1.13更新后具有更多的格式: --方块id参数 命名空间:方块id[方块状态]{方块nbt} --物品id参数 命名空间:物品id{物品nbt} 关于方块状态和物品nbt,我们以后再了解。 本章到此为止。 第三十章 方块 minecraft是由什么组成的? 答:是由方块组成的。 minecraft的一切事物,都是由方块组成的:玩家、动物、草、木、水、火、空气...... 关于方块,这个minecraft的基本元素,我们需要了解它,并深入它。 在minecraft中,其实一共就只有两个基本的类别:方块和实体。实体其实从某种方面来说,也是由方块拼搭而成的(像素),也包括你。 每个方块,都有自己的样子、数据值、nbt、英文代码、数字代码、方块状态等。在1.8以前,java版是用数字id来确定方块的,这个之前有讲过。 那么每个方块的基本性质是什么? 在minecraft中,一格被设定为等于现实中的一米。所以一块方块,是1立方米。在minecraft中,每个方块都对应了网格上面的一格,导致大部分方块不能具有多个单元。 方块通过重力的影响分为两类,无视重力方块和会被重力影响的方块。其中,前者占大多数。 会被重力影响的方块,可以说是屈指可数。到目前为止(1.15版本),会被重力影响的方块有:沙子、红沙、沙砾、铁砧、龙蛋、混凝土粉末、脚手架和顶层雪。 minecraft有很多种类的方块,那么,占比主世界网格最多的方块是什么呢? 首先大家一定会想到泥土方块。其实,泥土方块只排在第三名。 然后是石头对吧,其实石头也只能排在第二名。 其实,minecraft有一个非常容易被人忽视的方块,我在讲\/give时有提到过。它无色无味,无影无形。但是,它却遍布者整个世界,甚至在末地(末路之地)、下届(地狱)也存在着。 它是什么? 它,就是,空气方块(air)! 没错,空气方块遍布整个世界。如果脱离了空气方块(比如卡在沙子里),那么将会受到窒息的危险! 但好像空气也没什么值得说的了...... 现在的minecraft版本,很多方块已经无法获得的了。比如说:水方块、岩浆方块、下界传送门、吃了好几块的蛋糕、发光的红石矿、火、床的下面方块以及熄灭的红石火把等。 如果你通过了外部获得了它们,那么它们的材质(外观)将会是“丢失的材质”的材质。有时候网易版我的世界出现故障(bug)时,其世界的方块材质(外观)也会变成:丢失的材质。 方块的每一面都是16乘16像素的,但是可以通过改变外部文件来改变方块的材质,装材质包就是一个典型的例子。 但是,有些方块我们估计在新版无法再见到了: 哭泣的黑曜石(1.16又加回来了) 下界反应核 上锁的箱子 ...... 当然,通过指令,你还可以为方块添加上nbt。 历史 \\\\java\\\\ pre-ssic rd-——可以放置或破坏方块了 rd-——现在支持不同种类的方块,并加入了粒子效果和选择方块的功能。 ssic ?——加入了方块声音 ——可捡起并放置所破坏的方块,物品栏内物品可以堆叠和移除了。 ——现在需要按住鼠标才可以破坏方块,并加入了破坏方块的动画。 0.27_survival_test——生存测试,通过各种方块可以获得各种物品 0.28——可使用自然生成的方块用作建设 indev 0.31——方块可以掉落并捡起,同时方块可以放置在物品所在的位置上了。新的方块粒子效果。 正式版 1.7.2——由于方块英文id的加入,26种技术性方块无法再获取。 1.8——由于方块数值id的移除,12种技术性方块无法再获取。 1.9——燃烧的熔炉无法再获取。 \\\\携带版与基岩版\\\\ alpha pre-release——加入了专属的青花和隐形的基岩 0.2.0——可捡起并放置所破坏的方块,并且方块可以在物品栏中堆叠了 0.2.1——加入了动画效果 0.5.0——加入了专属的下界反应核 0.6.0——加入了专属的切石机 0.9.0——移除了青花 0.12.0——下界反应核无法在生存、创造中获得 0.13.0——移除了切石机的合称配方与功能 第三十一章 实体 之前我们一直提到『实体』,并简短的介绍了它。但是,实际上这还不够全面。 在生存时,船和矿车是经常可以用到的载具。其实,它们作为一种实体,是有生命值的。所以,当你回收这些道具时,相当于把它们打死(事实上就是这样的),所以在击打它们时,会出现摇晃的效果。 还有,之前提到过『下落的方块』,这是一种可以变成方块的实体。实体和方块是怎么转换的呢? 还记得上一章的『受重力影响的方块』吗?它们在下落时统称为『下落的方块』。在下落时,方块变为实体;到达地面时,实体变为方块。 所以,一般的,实体具有速度、位置和旋转角度。大部分实体还具有如下特征: 1.具有碰撞箱(网易版中已移除的mod实体除外) 2.会着火 实体主要有以下种类: 动物、掉落物、弹射物、实体方块、载具、其他 其中,动物又可以分为被动形生物(无害的生物)、中立生物、以及攻击性生物;也可以分为水生生物、寒带生物、热带生物、草原生物、地狱生物、末地生物、亡灵生物、节肢生物。 掉落物就是掉在地上的物品,叫做掉落物。 弹射物就千奇百怪的了,除了普通的箭,还有羊驼喷出的痰、末影龙的龙息等。 但你知道吗,原版mc里不用指令能达到的最高伤害正是你把恶魂的火球反弹后的火球,其伤害高达1000点!秒杀末影龙! 实体方块(非方块实体),也就是之前说过的下落的方块、点燃的tnt这些由方块变成的实体。 载具,也就是船啊这些可以帮助玩家行进的东西。 实体也可以相互组合,即骑行。比如鸡骑士(鸡+小僵尸)、蜘蛛骑士(蜘蛛或毒蜘蛛+骷髅),载者玩家的矿车、船、猪。甚至,还有在矿车载着骑着猪的玩家、船上有一个鸡骑士和骑着骷髅马的骷髅(这个算起来有5种实体了)。甚至,还可以通过指令生成一个僵尸骑着僵尸再骑着僵尸然后有两种这样的“僵尸塔”在船里(禁止套娃)。 历史 java 1.1——玩家在创造模式下不再能与超出手能够到的距离的实体交互 1.4.2——实体现在可以穿过传送门 1.9——稍微更改了弹射物的运动机制,现在玩家的某些特定运动也会影响到弹射物轨迹(坠落、使用鞘翅飞行、被击退时的动力)。同时,大部分实体可以被另一个实体推动。 1.11——大改了实体id,全部使用小写形式,该空格的地方使用下划线『_』代替,并且支持了命名空间。同时,人类idmonster和拉娜、史蒂夫(生物)、黑史蒂夫、野兽小子的idmob被移除。 1.16——更改了实体uuid,同时nbt标签angryat现在对所有实体都管用,而不止玩家(来自俄语minecraft wiki) 携带版alpha ?——生物内部不再渲染 基岩版 ?——生物内部再次渲染 ps:在第四章中,本书这么介绍到实体 『简单且不严谨地来说,实体指的是非方块的东西,比如玩家、生物等都是,还有例如掉落的方块、点燃的tnt也是实体。』 正如这句话开头所言,这是很不严谨的。因为在minecraft中,除了方块和实体,还有粒子效果、天空(本质上是贴图)等等等等其他的东西,而这些东西都不是实体。所以,实体并不是单纯指的是非方块的东西。之所以我在第四章这么介绍,那是因为得顾及一下你们的学习阶段,一上来就讲这么复杂的话可能会让很多人搞不懂。 第三十二章 tickingarea-基岩版控制常加载区块 在“第二十八章——区块”中,我曾提到过java版和基岩版分别有一条指令用于控制常加载区块。 在基岩版中,这条指令是:\/tickingarea,即一直执行游戏刻(ticking)的地区(area)。 \/tickingarea 作用:增加、减少或查看常加载区块。 需要权限等级:1 需要作弊:是 格式: \/tickingarea add <起点方块坐标><终点方块坐标>[此区域名称:字符串] \/tickingarea add circle <区域圆心坐标><区域半径:整数>[此区域名称:字符串] \/tickingarea remove <地区位置:坐标> \/tickingarea remove <地区名称:字符串> \/tickingarea remove_all \/tickingarea list [维度选项:all-dimensions] 书接前文,那个我的世界网易版租贷服在建完回城雪球后,发现一个问题:有时候这雪球不灵。 经过腐竹的仔细排查,发现是因为该命令方块链所在的区域虽然是在主城正下方,但因为基岩版并没有出生点区块,就导致有时候主城里玩家都跑光了,区块停止加载,回城雪球就不管用了。 为此,这位腐竹使用了以下指令: \/tickingarea add 303 100 92 343 20 52 home 这条指令的作用是: 将与(303,100,92)到(343,20,52)这块区域有重叠部分的所有区块列为常加载区域,并取名为home。 其中,选取区域的模式和\/fill是一样的,即选定区域的对角坐标。虽然这里选取时有使用y轴,但由于区块并不考虑y轴,其实没多大用处。 游戏并不会将选取的区域直接列为常加载区域,而是会将与选取区域有重叠部分的所有区块(哪怕只有那么一块方块)列为常加载区域,不然游戏计算时就非常麻烦(因为精确到了每个方块)。 也就是说,哪怕你只选取了一格方块,也会将该格方块所在的区块列为常加载区域。 在使用这条指令过后的第三天下午,服务器的mspt突然从原本的39ms\/t~57ms\/t暴增到了265ms\/t~527ms\/t,最高值甚至达到了3761ms\/t。虽然网易租贷服看不到那么直接的数据,但直观上的游戏卡顿已经快到玩不下去的地步了。腐竹接到管理员的消息过后,立马进服排查问题(因为存档上一次备份还在一个月前)。在忍受了数小时的超高延迟后,终于找到了问题: 主城范围冒险并没有覆盖到主城的地下,但这儿仍然是常加载区域。一位资深熊孩子在一个月前尝试炸服无果后,仔细钻研最终发现了这个漏洞。于是在主城的地下搞出了大量已经命名的生物(非法获取到刷怪蛋,命名后放入发射器,配备专门研制的高频红石)。这些被命名的生物无法消失,又因为处于常加载区块,造成了服务器卡顿。 腐竹为了解决这个问题,使用了如下指令: \/kill @e[type=!yer,r=50] \/kill @e[type=item,r=50] (此时服务器在经历一阵达好几万mspt的卡顿后,终于顺畅了许多,然后腐竹就拆掉装置了,并将需要常加载区域的东西全部转移到了一个很远很远的地方) \/tickingarea remove home \\\\移除名为home的常加载区域\\\\ \/tickingarea add circle 21 2 mand \\\\将与以(,21,)为圆心的半径2区块(32格)的圆有重叠部分的所有区块列为常加载区域,并取名为mand\\\\ 其中,移除常加载区域时,如果当时这位腐竹并没有设定该常加载区域的名称,那么它只能这样做: \/tickingarea remove 323 65 72 这条指令会删除所有包含该坐标点的常加载区域。 如果这位腐竹忘记了该常加载区域的名称,或者是忘记了它的位置,那该怎么办? 它有两种选择,第一种是: \/tickingarea remove_all \\\\删除所有常加载区域\\\\ 第二种是: \/tickingarea list \\\\列出当前纬度所有常加载区域\\\\ 第二种方法中,list返回的信息是这样的: 当前维度中的所有常加载区域的列表 -区域名:x yz到x y z -区域名(圆形):x y z 半径:1~4区块 0~10\/10常加载区域正在使用 别看就短短这几行,信息量还是很大的。 首先,方形区域会直接显示区域的对角坐标。这个对角坐标并不是添加时填写的对角坐标,而是经过重叠部分转化成的实际加载区域的对角坐标。圆形区域会显示该区域转化过后的中心点和设定的半径。最后会显示目前有多少常加载区域和常加载区域上限。 常加载区域数量还有上限?没错。一个存档最多添加10个常加载区域,每个常加载区域的区块数不能大于100。 圆形区域是什么?这就要看这个腐竹用的最后一条指令: \/tickingarea add circle 21 2 mand 这条指令的意思上面已经讲过,这儿就不复制过来了。 圆形区域顾名思义,就是圆状的常加载区域。它有两个重要参数:圆心和半径 圆心坐标和方形区域填写的两个坐标一样,实际上y坐标没多大用。而半径,它的单位不是格而是区块。 半径必须是1、2、3、4这四个整数,即16格、32格、48格和64格。 确定了圆的范围后,游戏就会进行和方形区域一样的操作:将与该圆重叠的所有区块列为常加载区域。 这就是圆形区域。 现在,\/tickingarea这条指令差不多就讲完了,但还没有完全讲完,因为还有一个参数没讲: list的维度选项。 维度选项参数只支持一个值:all-dimensions,即所有维度。使用了: \/tickingarea list all-dimensions 将不只是列出基准点所处维度的所有常加载区块,而是列出所有维度的所有常加载区块。 历史 基岩版 1.2.0——加入了常加载区域和配套的\/tickingarea。 第三十三章 execute-这年头,猪都会说话了 在minecraft有一个很有意思且功能强大的指令。 没错,它就是:\/execute。 这是一个相当有用的指令,我们会在以后经常碰见它。为何?因为通过它,你可以使一个或多个实体作为执行源像命令方块一样执行指令,甚至可以添加一些条件来判断是否要执行指令。 由于java1.12.2以上版本和java1.13以下版本、基岩版有很大的区别,所以今天我们只讨论java1.13以下和基岩版的格式,这样子讲起来比较简单。 \/execute 作用:使一个或多个实体分别作为执行者执行指令 需要权限等级:java-2,基岩-1 需要作弊:是 格式(基岩版、java1.13更新前): \/execute <执行者:目标选择器><基准点:坐标><执行的指令> \/execute <执行者:目标选择器><基准点:坐标> detect <探测的坐标><方块id><方块数据值><执行的指令> execute有什么用呢?它可以更改执行指令者和执行指令的基准点,如果有多个执行者则会每一个执行者都执行一遍指令。更进一步可以检测某个坐标的方块是否符合条件,符合条件就会执行指令。比如我们要让猪说话,就可以: \/execute @e [type =pig ]~~~ say 你好! 这条指令可以将所有猪作为执行者,它们的位置作为执行地点,分别执行『say 你好!』这条指令。这样子,主世界内的所有猪都会说:“你好!”了。 你无聊的时候,还可以像这样子: \/execute @e ~~~ execute @e ~~~ execute @e ~~~ execute @e ~~~ execute @e ~~~............... (没错作者在套娃) 使用execute,就可以干一些特别的事了。比如: \/execute @a ~~~ setblock ~~-1 ~ diamond_block 这条指令将所有在线玩家作为执行者,他们的位置作为执行地点,分别执行『setblck ~~-1 ~ diamond_block』指令,在他们的脚下放置一个钻石块。这样子,所有玩家的脚下就会生成一个钻石块。 使用execute甚至可以毁灭世界。这样子写: \/execute @e [type =item]~~~ fill ~-1 ~-1 ~-1 ~1 ~1 ~1 air destroy 这个是什么意思呢? 这样子写,如果有一个掉落物,那么这个掉落物就会破坏掉其周围的3x3的空间,并且其破坏掉的方块都会掉落成掉落物。然后这些掉落物又会破坏掉周围3x3的空间,然后掉落,扩大,再破坏、掉落、扩大.......。如果在重复、无条件的命令方块里运行,你的电脑(或手机)会在1游戏刻内到1秒内卡死。因为这个比2的次方还要恐怖。 然后是detect。 前文说到,一个网易我的世界租贷服搞了一个回城雪球。后来,另一个服务器的腐竹由此受到启发,开发了一个“回城红石块”。 这个回城红石块很简单,只需要一个命令方块: a→ a:重复执行,无条件,始终活动 \/execute @a ~~~ detect ~~-1 ~ redstone_block 0 tp @s 30 64 24 这条指令的意思是:将所有玩家作为指令执行者,当其脚底下是数据值为0的红石块时,传送他们自己到(30,64,24)。 其中,参数『方块数据值』可以填写-1来代指不判断数据值。在java1.11及以上版本,这个参数还可以填写方块状态,并用星号『*』来代指所有方块状态(也就是不判断方块状态)。 比如: \/execute @a ~~~ detect ~~-1 ~ minecraft:magenta_zed_terracotta facing=south tellraw @s [{“text“:“该箭头朝向“,“color“:“yellow“},{“text“:“北方“,“color“:“light_purple“}] 这条指令的意思是:将所有玩家作为指令执行者,他们的位置作为指令执行地点,如果他们脚下的方块是朝向南方的品红色带釉陶瓦(也就是上面有箭头的那一个粉色方块),就告诉他们『该箭头朝向(黄色)北方(浅紫色)』。 现在,你应该能看得懂那个回城雪球的第一条指令吧?尝试理解一下: \/execute @e[type=snowball]~~~ execute @p[r=1.5,rx=90,rxm=60]~~~ execute @e[type=snowball,c=1]~~~ tag @s add back_home (实际上这条指令还有一个更好的替代方案: \/execute @a[rx=90,rxm=60]~~~ execute @e[r=1.5,type=snowball,c=1]~~~ tag @s add back_home ) 历史 java 1.8——加入了\/execute命令。 1.11——\/execute支持方块状态 1.13——\/execute的语法被拆分 携带版alpha 0.16.0——加入了\/execute 第三十四章 setworldspawn、spawnpoint-出生点 很久很久以前我们就已经提到过出生点(重生点)了。如果没有记录床时就会重生在出生点。 但是,如果要制作一张地图,出生点和复活点(存档点)是必不可少的。那么,怎么才能更改出生点和重生点的位置呢? minecraft允许我们用两种指令更改出生点和重生点。这两种指令的作用猛的看相似,仔细一研究就会发现其并没有那么简单。 这两种指令就是:\/setworldspawn和\/spawnpoint。 先来看看第一种。\/setworldspawn这个很长吧,不好记。其实,把它拆开,就好记了。 setworldspawn其一共是由三个单词组成的:set、world和spawn。set之前见到过,意为“设置”,world的中文意思是“世界”,spawn的中文是“产卵、产生”。 那么这样子就可以大致的知道setworldspawn的意思:设置世界的产生地。 这样子总有些怪怪的。其实英文本身语法跟中文不同。所以,正确的翻译是:设置世界的出生点。 \/setworldspawn 作用:设置世界(玩家)出生点。 需要权限等级:java-2,基岩-1 需要作弊:是 格式: java1.16及以上版本 \/setworldspawn [<坐标>][<水平旋转角度>] 基岩和java1.16以下版本 \/setworldspawn [<坐标>] 使用\/setworldspawn可以设置世界玩家出生点。如果不写坐标默认就是执行者的坐标,不写旋转角度默认是0.0,即朝正南方。比如: \/setworldspawn 261 80 81 90 即设置世界出生点为(261,80,81),出生或重生时朝向正西。 需要注意的是,如果该游戏存档默认不是冒险模式,y轴会被无视,玩家会直接出生或重生在该坐标的y轴最高点。默认冒险则可以解决这个问题,只不过如果设定的出生点没有空气,出生点还是会往上移动直到有空气的地方,最高到256格(1.18预览版为319格)。 还有一点需要注意的是,如果要让玩家精确无比地生成在该坐标,游戏规则spawnradius就要设为0,不然生成点最大会偏移10格(java)或5格(基岩)。 使用\/setworldspawn可以解决世界出生点和重生点的问题。但在服务器或是专门给多人玩的小游戏地图中,玩家的重生点并不是在一起的,那该怎么办? 使用\/spawnpoint。 \/spawnpoint,由spawn和point组合而成。point即“点”的意思,也就是说,spawn point就是出生点的意思。只不过它设定的并不是世界的出生点,而是单个或多个玩家的重生点。 \/spawnpoint 作用:设定一个或多个玩家的重生点。 需要权限等级:java-2,基岩-1 需要作弊:是 格式: java1.16及以上版本 \/spawnpoint [<玩家:目标选择器>][<坐标>][<角度>] 基岩和java1.16以下版本 \/spawnpoint [<玩家:目标选择器>][<坐标>] 如果只填上\/spawnpoint,那么将会设定自己的重生点于自己的位置。 如果填上目标选择器,不填坐标,那么将会设定目标的重生点于自己的位置。 如果全部都填,那么将会指定目标的重生点于指定的坐标。 那么这两个指令有什么不同呢? \/setworldspawn是设定世界默认出生点,会影响到设定后进入的玩家,但不会覆盖\/spawnpoint。 \/spawnpoint是设定单个或多个玩家的重生点,一般用于制作地图中的存档点(又叫重生点),但不会覆盖床。 比如: \/execute @a ~~~ detect ~~-1 ~ diamond_block 0 spawnpoint 这条指令的效果是:当任意一名玩家站在钻石块上时,就会设定他的重生点于此地。 \/spawnpoint固然好用,但重生点设定之后就无法移除,只能通过\/spawnpoint再次设定地点以覆盖。为此,mojang搞了一个专门解决重生点的指令: \/clearspawnpoint 作用:清除一名或多名玩家的重生点。 需要权限等级:1 需要作弊:是 版本独占:基岩版 格式: \/clearspawnpoint [<玩家:目标选择器>] 默认是清除执行者自己的重生点。 这条指令哪都好,就是目前它是基岩版独占。 历史 \\\\java\\\\ ssic 0.0.17a——加入了\/setspawn用于设置世界出生点 indev 0.31——移除了所有命令 正式版 1.4.2——加入了\/spawnpoint 1.7.2——加入了\/setworldspawn 1.9——加入了spawnradius游戏规则 1.16——\/spawnpoint现在在任意维度都可以使用 1.16.2——为\/spawnpoint和\/setworldspawn添加了朝向参数 \\\\携带版和基岩版\\\\ alpha 0.16.0——加入了\/setworldspawn和\/spawnpoint 基岩版 1.12.0——加入了spawnradius游戏规则 1.16.0——\/spawnpoint可以在下界使用 1.16.100——加入了\/clearspawnpoint ....... ....... ....... 如何获取一个玩家的重生点位置? 使用: \/getspawnpoint 作用:获取单个玩家的重生点坐标 需要权限等级:3 需要作弊:否 版本独占:基岩版、教育版 不显示在命令列表里:是 格式: \/getspawnpoint <玩家:目标> 由于此命令需要在基岩版服务器中使用,而且因为权限等级过高又隐藏在命令列表,故作者没有对此详细研究。 ...... ...... ...... 第三十五章 spreadplayers-随机传送 前文说到,一位minecraft java服务器的腐竹,为了实现将宝箱随机放在世界各处,使用了如下指令: \/summon minecraft:armor_stand ~~~{customname:“\\“a\\““} \/spreadyers ~~ 32 false @e[type=minecraft:armor_stand,name=a] \/execute as @e[type=minecraft:armor_stand,name=a] at @s run ......(后面省略) 其中,第二条指令\/spreadyers我们还没了解过。那么\/spreadyers有什么用呢? 随机传送实体(分散[spread]玩家们[yers]) \/spreadyers 作用:将一名或多名实体分别传送到指定范围内随机一个地方 需要权限等级:java-2,基岩-1 需要作弊:是 格式: java1.15.2以上 \/spreadyers <中心坐标:x><中心坐标:z><最小间距:小数><范围边长?><考虑队伍:布尔值><实体:目标选择器> \/spreadyers <中心坐标:x><中心坐标:z><最小间距:小数><范围边长?> under <最大高度:y><考虑队伍:布尔值><实体:目标选择器> java1.16以下 \/spreadyers <中心坐标:x><中心坐标:z><最小间距:小数><范围边长?><考虑队伍:布尔值><实体:目标选择器> 基岩版 \/spreadyers <中心坐标:x><中心坐标:z><最小间距:小数><范围边长?><实体:目标选择器> 随机传送的范围是一个默认在世界建筑高度限制的正方形(注意,不是正方体),确定这个范围大小时是填写这个范围边长的二分之一(比如边长是200,范围边长?就填100)。需要注意,“范围边长?”这个参数的值不能小于“最小间距”。如果填写了under,可以规定传送的最大高度。这个参数并不只是单纯的将这个正方形从世界建筑高度限制拉下来,而是还有个作用: 随机传送时,实体就不会被传到高空然后掉下来摔死,而是会直接来到y轴最高的方块上(注意,这个方块的y坐标不能大于最大高度参数的值)。 随机传送的实体可以有很多个,但每个实体在不考虑队伍的情况下都是单独传送。既然是单独传送,就有可能有两个或更多实体挨得很近。所以,最小间距也是个很重要的参数,它规定了随机传送时实体们的最小间距。比如随机传送参数的值为7,那么执行时就算有两个实体随机到了很近的地方,它们的距离也绝对不会小于七格。 举个例子,比如: \/spreadyers 100 100 30 300 under 128 true @a[tag=hunger_games_teams] 执行时会先确定范围:一个中心在(100,100)的正方形,边长为600格。随后将以队伍为单位,随机传送所有具有hunger_games_teams标签的玩家类队员到该范围内,并且直接来到y轴最高(但不能超过128格)的方块上面,且两个队伍间距最小为30格。 \/spreadyers并不只可以随机传送玩家,正如那位将宝箱随机放在世界各处的腐竹用\/spreadyers随机传送盔甲架一样,\/spreadyers还可以随机传送任何实体。 所以,\/spreadyers可以用在服务器具有大场地的任何玩法中,如资源区(随机传送玩家)和吃鸡玩法类型游戏(随机传送玩家、空投箱)。 历史 java 1.6.1——加入了\/spreadyers 1.16——加入了“under”和“最大高度”参数 携带版 1.0.5——加入了\/spreadyers 第三十六章 testfor -探测 上 如果你想知道现在有多少个玩家,可以打开设置界面或按下tab键就可以查看有多少个玩家。如果你想知道有多少个指定实体,那么你需要............一条指令。 这条指令是什么指令呢?它就是:\/testfor。 \/testfor 作用:探测有多少个指定实体。 需要权限等级:1 需要作弊:是 版本独占:基岩版、教育版、java1.13之前版本 格式: java1.13之前 \/testfor <指定目标:目标选择器>[探测nbt是否符合] 基岩版 \/testfor <指定目标:目标选择器> 你是不是以为有什么坐标,但其实一个目标选择器就够了。 比如探测玩家boybook是否在线,可以这么写: \/testfor boybook 一直重复执行,并用红石比较器检测是否有输出信号。如果有,则在线,反之则下线。 假设我们要检测每个玩家周围100格内有多少只苦力怕,就可以: \/execute @a ~~~ testfor @e[type=creeper,r=100] \/testfor这条指令很简单,但相比其他大多数指令,它有一个特别的功能: 输出探测到的实体数量,转化为红石信号强度。 那么就需要用到:红石比较器了。 首先,把红石比较器的比较那一端对准写了\/testfor的指令的命令方块。 然后(不要加上中继器),将红石线延长到15。 接下来,打开命令方块。 如果写着刚才探测苦力怕的指令。假设探测到了12只苦力怕。 那么命令方块上一个输出就是12只苦力怕,而输出的红石信号强度也为12(12格)。 这样子,就可以从外面看到数据了。 但是,由于红石信号最高15格,所以我们只能:在里面看到最真实的数字,外面最高只可显示15。 历史 java 1.5——加入了\/testfor 1.8——\/testfor支持nbt标签探测,并不再为命令方块独有 1.13——\/testfor被移除 携带版 1.0.5——\/testfor 第三十七章 testforblock、testforblocks-探测 下 我们现在学会了如何探测实体,那方块呢? 使用\/testforblock和\/testforblocks。 这两个指令只相差1个字母,但是功能却大径相庭。在英文中,blocks是blcok的复数。也就是说,\/testforblock是探测单个方块,而\/testforblock是探测多个方块。 真有这么简单吗? \/testforblock 作用:探测指定位置是否为某种方块。 需要权限等级:java-2,基岩-1 需要作弊:是 格式: 基岩版 \/testforblock <探测位置:坐标><方块id:字符串>[数据值:整数] java1.13之前 \/testforblock <探测位置:坐标><方块id:字符串>[数据值:整数] \/testforblock <探测位置:坐标><方块id:字符串>[方块状态] 很不幸的是,虽然java版和基岩版都有加入这条指令,但是java版中这条指令在1.13版本的第三个快照时被移除了。所以说: \/testforblock in java 生于1.7.2版本13w37a 死于1.13版本17w45a 算了,正经点。 举个例子,比如: \/execute @a ~~~ testfor ~~-1 ~ minecraft:redstone_block 就是探测每个玩家其脚底下是否是红石块,是则成功,否则失败。 然后是\/testforblocks。刚才说过这里多了s,也就是多个方块,那么是怎么探测的呢? 先来个介绍: \/testforblocks 作用:探测指定区域是否与另外一个指定区域完全相同 需要权限等级:java-2,基岩-1 需要作弊:是 格式: \/testforblocks <源区域起始坐标><源区域终止坐标><比较区域下西北角坐标>[<模式:masked|all>] 比较时先通过\/fill选择区域的方式确定源区域,再与要比较区域进行比较。只不过这个要比较区域的位置填写就挺蛋疼:你得找到要比较区域的下西北角(专业术语叫做区域基点)。 哪里是下西北角呢? 区域内xyz三个值最小的地方。 这两个区域的大小由第一个定,所以比较的区域就直接给一个角了。 以后的\/clone指令(复制指令)也是这种形式。 举个例子: \/testforblocks ~-1 ~-1 ~-1 ~1 ~-1 ~1 ~-1 ~2 ~-1 作用是:检测执行者脚下3x3的区域是否和头顶3x3的区域完全一样 \/testforblocks还有两个比较模式: all和masked。 all(默认模式)——比较全部。 masked——忽略源区域的空气方块(即源区域的空气方块可以代替要比较区域的任何方块) 这两章所讲的3条指令,要发挥全部作用就需要和红石比较器配合,不只是单单的用命令方块执行哦! 历史 java 1.7.2——加入了\/testforblock 1.8——加入了\/testforblocks 1.11——\/testforblock支持方块状态 1.13——因为execute if的出现,\/testforblock和\/testforblocks被移除。 携带版alpha 0.16.0——加入了\/testforblock和\/testforblocks 第三十八章 replaceitem-头上顶着一个tnt 这是一个很牛逼的指令。 真的真的很666。 它就是: \/receitem 首先,\/receitem其实由rece和item组成。rece,之前见到过,意为“代替”;item,之前见到过,没讲过,它在minecraft中意为“物品”。所以,receitem意为“代替物品”。 \/receitem 作用:替换容器方块或实体物品栏内的物品。 需要权限等级:java-2,基岩-1 需要作弊:是 格式: java1.17以前 \/receitem block <方块位置:坐标><栏位><物品>[数量] \/receitem entity <实体:目标选择器><栏位><物品>[数量] 基岩 \/receitem block <方块坐标><栏位类型><栏位编号>[<原物品处理:destroy|keep>]<物品>[数量][数据值] \/receitem entity <实体:目标选择器><栏位编号>[<原物品处理:destroy|keep>]<物品>[数量][数据值] \/receitem的block(方块)和entity(实体)格式,差别就只是选定的方式和栏位有所不同。 什么是栏位呢? minecraft中任何可以放置物品的格子,都是栏位。一个栏位的身份由栏位类型和栏位编号组成。 在java版中,栏位类型和栏位id是合并在一起的: slot.<类型>.<栏位编号> 比如slot.enderchest.2(末影箱第一行从左往右第三格) 在基岩版中,栏位类型和栏位id是分开的: slot.<栏位类型>空格<栏位编号> 比如slot.armor.head 0(生物的帽子栏位) 怎么判断栏位编号呢? 最上面一排左边的第一个格子的栏位被编号为0,而后从左到右、从上到下递增(例如,箱子的第一行栏位被从左至右编号为0至8)。但是注意一点:大型箱子与大型陷阱箱被视为两个独立的容器方块,也就是说你选中箱子的左边,那么只能控制一半;选中箱子的右边,也只能控制一半。 酿造台底部栏位从左至右编号为0至2,而其顶部栏位为3。 熔炉的栏位中输入栏的栏位编号为0,燃料栏的栏位编号为1,而输出栏栏位为2。 现在举个例子: \/receitem entity @a slot.armor.head minecraft:tnt——java1.17之前 \/receitem entity @a slot.armor.head 0 tnt——基岩 这条指令的作用是:让所有玩家头上都顶着一个tnt。 使用\/receitem甚至可以修改末影箱内的东西。比如: \/receitem entity @s slot.enderchest.16 minecraft:diamond 64——java1.17之前 \/receitem entity @s slot.enderchest 16 minecraft:diamond 64——基岩 作用是:将执行者自己的末影箱第二排第八格替换成64颗钻石 \/receitem好是好,但这样子替换东西原来的东西就没掉了。 那该怎么办? mojang给了我们两个替换模式: destroy和keep destroy——默认方式,直接替换 keep——如果该栏位已有物品则不替换 比如: \/receitem entity @s slot.enderchest 0 keep minecraft:air——仅基岩1.16及以上版本 这条指令的作用就是:如果自己的末影箱第一个栏位没东西,那么替换个空气;如果有,那么啥事也没有。 真?替换了个空气 现在你学会了\/receitem了吧?但是有件事情得注意:像这样子乱戴(不按常理出牌)只有在java版才有显示,基岩版没有显示。但是除玩家以外大部分都有显示(比如僵尸)。村民两个版本都不显示,就算你给他们带上钻石头盔等正常的东西。但是虽然不显示,却有作用。 历史 java 1.8——加入了\/receitem 1.14——\/receitem现在支持物品展示框 1.17——被\/item取代 携带版和基岩版 1.0.5——加入了\/receitem 1.1.0——\/receitem现在支持canceon和candestroy物品组件 1.16.0——为\/receitem添加了替换模式参数 第三十九章 particle-在mc里做特效 mc里有一种东西,会在很多地方出现。它不会伤及到任何人,也不会和方块互动。 它经常在岩浆上跳跃;经常在拥有效果的玩家身边出现;也经常在地下的红石矿周边逗留。 它是什么?粒子效果。 粒子效果很容易被忽视,因为它没有实际的作用,只是一种特效。但是如果没有粒子效果,那么整个minecraft将会发生一次大改变:岩浆不再向外喷火、玩家有效果时不再有外部提示、破坏方块再无特效...... 因为使用粒子效果可以更好的建设minecraft,所以粒子特效被很多大型服务器所用。 看起来粒子效果很高级。其实,使用粒子效果只需要一条指令:\/particle。 \/particle,意为“粒子、颗粒”。所以,其大致的功能就已经猜到了:肯定跟粒子有关系(不然为何使用了200多字讲粒子)。在很多指令玩家中,\/particle有一个外号:“粒子发射器”。 \/particle 作用:在一个区域内生成一些粒子。 需要权限等级:java-2,基岩-1 需要作弊:是 格式: java1.12.2之后 \/particle <粒子id><坐标:xyz>[<延伸坐标:dxdydz>][速度][数量][模式:force|normal][目标玩家:目标选择器] java1.13之前 \/particle <粒子id><坐标:xyz><延伸坐标:dxdydz><速度>[数量][模式:force|normal][目标玩家:目标选择器][参数] 基岩 \/particle <粒子id><坐标> \/particle最简单的使用方法就正如基岩版一样,一个粒子id加坐标就搞定了。比如: \/particle bubble ~~~ 就可以生成一个泡泡粒子。 下面作者列出一些粒子id: hugeexplosion——超大爆炸 rgeexplode——大型爆炸 ireworksspark——烟花火箭飞起来的特效 bubble——泡泡 crit——跳劈击打的效果 smoke——烟雾 mobspell——黑色圈形颗粒 spell——白色圈形颗粒 instantspell——白色x形颗粒 note——音符盒的音符 portal——地狱门和末影人周围环绕的紫色颗粒 enchantmenttable——从书架飘向附魔台的文字(听说这个有点意思) explode——爆炸 me——刷怪笼刷出一次怪物时出现的火花 va——岩浆飞溅出的火花 footstep——脚印(好像在某些版本时玩家走路时会有脚印粒子) ssh——溅起的水花 rgesmoke——大型烟雾 cloud——云(类似烟雾) reddust——黑色的颗粒 snowballpoof——雪球打到生物时雪球破碎的效果 dripwater——天花板滴下的水 driva——天花板滴下的岩浆 snowshovel——白色的颗粒 slime——史莱姆跳动时的绿色粒子 heart——爱心 wake——蓝色的颗粒 mobspembient——淡灰色的圈形颗粒 angryviger——村民生气的粒子 happyviger——村民快乐的粒子 ............................................... 如果你对这些粒子不满意,你还可以自定义粒子效果。 在java1.13版本,使用dust、block和item可以自定义一些粒子效果: dust可以自定义粒子烟雾的颜色: \/particle dust <红色占比><绿色占比><蓝色占比><大小>...... 这里的四个值以1为100%,从0.0开始,到1.0。比如生成一个30大小的蓝色粒子: \/particle dust 0 0 1 30 ~~~ item可以生成指定物品被破坏时的粒子: \/...... item <物品id>....... 比如生成一个钻石被破坏的粒子效果: \/particle item diamond ~~~ block可以自定义破坏方块显示的粒子: \/particle block <方块id>....... 比如\/particle block mand_block ~~~,就可以生成一个破坏命令方块时的粒子效果。 在java版,\/particle有更多的参数可以自定义: 延伸坐标——还记得之前讲的目标选择器的“dx”、“dy”、“dz”吗,这里的延伸坐标就是这个意思。不记得的赶紧回到第二十五章:更加精确的目标选择器。指定后粒子效果会均匀生成在指定的范围内,在1.13版本之前为必填项。 速度——指定颗粒飞行的速度。默认是0,且至少为0,在1.13版本之前是必填项。 数量——指定颗粒生成的数量,不填默认为0,且至少为0(产生一个粒子)。 模式——指定颗粒的显示模式,可以选择“force”和“normal”。 force:强制设置颗粒的显示范围为256格,包括已经设定好颗粒效果的可视距离的玩家。 normal:正常情况(默认的情况,真的是正常的) 目标玩家——指定可以看到该粒子效果的玩家。 举个例子: \/execute @a ~~~ particle heart ~~1 ~ 0 -2 0 3 10 normal @s——仅java1.13之前 上面这条指令的作用是:在所有玩家身上显示10个朝上飘的爱心,并且此粒子效果只能由该玩家看到。 在java版1.13版本之前,没有dust、block和item该怎么自定义粒子效果呢? 看到那个在java1.13被移除的叫做参数的参数了吧?这个参数只能在粒子id是blockdust、iconcrack、blockcrack和fallingdust时修改。 唉,发现了没有? blockdust是方块破坏时的粒子,blockcrack是方块挖掘时的粒子,在1.13中合并成了block粒子效果。iconcrack是物品破坏时的粒子效果,对应了1.13版本更新后的item。fallingdust是烟尘效果,对应了1.13版本之后的dust。 blockdust和blockcrack的参数是这样的: 最终参数值=方块数字id+方块数据值x4096 我勒个去,mojang你是神.....好吧,举个例子,假设你要在java1.12.2搞到红色羊毛被破坏的粒子效果,那么你就得先知道羊毛的数字id是35,然后知道红色羊毛的数字id是14,再然后通过计算器计算: 35+14x4096 35+ 最后输入指令\/particle blockdust ~~~ 1 1 1 0 10 normal @s 。 恭喜你,你搞到了红色羊毛的粒子效果! 需要注意的是,这里仅支持数字id,不支持字符串,所以这里也算是minecraftjava1.8更新时的一个残留。 fallingdust也不同于1.13版本后的dust,颜色并不能自定义,而是有一个现在已经很难找到的颜色id。 iconcrack和1.13版本后的item差别不大,其参数有两个(mojang你终于智商在线了),分别是物品数字id和数据值。 在java1.13之前的版本fallingdust并不能自定义颜色,但这不代表没有粒子效果可以自定义颜色。 当粒子效果是reddust、mobspell或mobspembient时,延伸坐标、速度和数量参数将不再是普通的参数,而是: 延伸坐标——速度参数>0、数量=0时,为粒子颜色rgb值,1为100%,dx为红、dy为绿、dz为蓝。 速度——不等于0且数量=0时,作为颜色rgb值的乘数 数量——为0时可自定义,大于0时颜色会随机(即变成彩色),并且延伸坐标和速度变为本来的作用 神奇的是,这三个粒子效果在1.13版本更新后还在,只不过稍微有亿些改动: reddust变成dust,并拥有了自己的格式。 mobspell和mobspembient变成了entity_effect和ambient_entity_effect,虽然没有自己的格式,但原本的延伸坐标作为rgb颜色值的格式仍在,且格式基本差不多,甚至在java1.17.1版本中都还可以使用这个及其离谱的格式! (本章于2021年8月末大修时大改) 历史 java 1.8——加入了\/particle命令和force显示模式 1.9——加入了“目标玩家”和“参数”参数 1.13——更改了粒子名称,“参数”参数惨遭删除,将部分\/particle参数改为选填。加入了dust、block、item特殊格式,移除了fallingdust、blockdust、blockcrack和iconcrack。 基岩版和携带版 1.0.5——加入又移除了\/particle 1.8.0——又加入了\/particle 1.9.0——加入了一些新的粒子 1.12.0——加入了些新的粒子 第四十章 记分板是什么鬼 相信很多人都玩过电子游戏。 就算你从来都没玩过电子游戏,只要你用过计算机,你就会发现在计算机上有一些数值会一直变化。比如时间、银行卡存款、股票价格等等。 像这种会变的数值,有一个专门的名称:变量。 相对应的,还有不会变化的数值,也有一个专门的名称:常量。 在minecraft中,你常常会看到各种变量——经验值、物品数量、状态效果等级等等。不难发现,变量的用途很广,如果能够在指令中使用变量岂不美哉? 在之前的章节中,我们学会了如何使用\/xp指令更改经验值。刚才有提到经验值就是个变量,加上经验值可以用于指令中,这不美哉? 但是经验值只是一项变量。如果我们想要创建一个属于自己的变量,那该怎么办呢? 没有法子。但是mojang给我们提供了另外一个东西:记分板(scoreboard)(又称“计分板”)。 什么是记分板?许多网页传奇常常为了刺激追求名利的玩家氪金,搞了许多排行榜。“战力榜”就是个典型的例子。在战力榜中,每个玩家的“战力”依靠某种顺序排列,一般是从大到小。同时,每个玩家的战力值都是实时变化的,也就是说“战力”是一个变量。 像这样的每个玩家都绑定了一项自己的变量,这个变量又靠某种顺序排列的排行榜,在minecraft中我们就可以称呼其为:“计分项”(又称记分项)。而用于承载计分项的东西我们就叫做“记分板”。 每个计分项都有以下几个信息: 名称(name)——该计分项的名称,用于指令中的调用,不可重名。在minecraft java1.18更新之前,计分项的名称不能超过16个字符。基岩版(最新版本)无限制。 显示名称(disy name)——在java版中是一串json文本,在基岩版中是一串普通文本。在一个计分项中不一定有这一个信息。主要用于游戏界面中名称的显示。在minecraft java1.18更新之前,显示名称不能超过32个字符。基岩版(最新版本)无限制。(更简单易懂的说法就是,名称就类似于你的qq号码,一经注册不可更改。显示名称则类似于你qq的昵称,可以随意更改) 准则(criterion [复数:criteria])——决定了计分项具体要跟踪的信息。比如我创建了一个准则是“deathcount”(死亡次数)的计分项,这个计分项自创建就会追踪每个玩家的死亡次数,然后列出一张“死亡榜”。最基本的计分项准则是dummy,即只能通过指令改变每个实体持有的分数的准则。准则有很多,在接下来的章节中我们会详细了解。 分数持有者(score holder)——正如其名,就是指计分项中每个变量(分数)所绑定的玩家或非玩家实体。 分数(score)——也就是变量。只不过相比普通的变量来说,这儿的变量是和玩家或非玩家实体绑定的,所以才叫“分数”。 举个简单的例子: 假设张三创建了一个名为“金钱”,显示名称也为“金钱”,准则为dummy的计分项。此时这个计分项由于刚创建里面没有任何东西,张三就使用指令给一名叫做“李四”的玩家在该计分项上添加了1分。由于“李四”并未在该计分项内拥有任何数据,于是游戏就帮助李四注册了一下这个计分项,并将李四的分数设定为0(初始值)+1。最终,这项计分项中就有一项“李四”的分数,并且其值为1。 现在你已经大概了解记分板是什么东西了吧?记分板有许多内容值得研究,下一章我们将会开始了解如何管理一个计分项。 第四十一章 objectives——管理一个计分项 如何创建并管理一个计分项呢?这就需要使用\/scoreboard。 \/scoreboard 作用:控制计分板 需要权限等级:java-2,基岩-1 需要作弊:是 格式(本章所涉及): \/scoreboard objectives ... java版 ... add <计分项名称><准则>[<显示名称:json>]——添加计分项(注:je1.13以下版本“显示名称”参数的值类型为字符串) ... list ——列出当前所有计分项 ... modify <计分项名称>...——对指定计分项进行一些更改操作[1.13更新] ...... disyname <显示名称:json>——更改指定计分项的显示名称[1.13更新] ...... rendertype ——指定显示该计分项数值时是采用爱心(hearts)还是数值(integer)显示[1.13更新] ... remove <计分项名称>——删除计分项 ... setdisy <显示位置>[计分项名称]——指定特定的位置显示指定的计分项或取消显示计分项。 基岩版 ... add <计分项名称:字符串><准则>[<显示名称:字符串>]——添加计分项 ... list ——列出当前所有计分项 ... remove <计分项名称:字符串>——删除计分项 ... setdisy <显示位置>[计分项名称:字符串][排序方法:ascending|descending]——指定特定的位置显示指定的计分项或取消显示计分项。 现在让我们来试一试。首先来尝试添加一个最基本的计分项: \/scoreboard objectives add coin dummy 金钱——仅java1.13以下和基岩版 \/scoreboard objectives add coin dummy “金钱“——仅java1.12.2以上 上面的指令将会添加一个准则为dummy,显示名称为“金钱”,叫做“coin”的计分项。 添加计分项时我们需要特别注意准则的选择。正如上一章所说的“准则决定了记分项具体要跟踪的信息”,一个计分项的作用,很大程度上是由准则决定的。 准则在基岩版只有dummy(虚拟型),在java版有两大类:单一准则和复合准则。 单一准则不可自定义,是mojang已经给你预设好的准则,目前有如下几种: dummy:虚拟型,最基础的准则,仅可通过\/scoreboard yers指令修改。 trigger:触发器,类似于dummy,但所有玩家均可修改自己的trigger型计分项。具体内容会在第九十八章讲到。 deathcount:玩家死亡次数,当玩家死亡时游戏会自动增加他的分数,可以通过指令修改。(java版的死亡榜就是这么搞的) yerkillcount:玩家击杀(玩家)数,当玩家击杀其他玩家时游戏会自动增加他的分数,可以通过指令修改。 totalkillcount:玩家击杀(生物)数,当玩家击杀其他任意生物时游戏会自动增加他的分数,可以通过指令修改。 health:玩家生命值,伤害吸收和生命提升的血也会计算在其中。当玩家第一次刷新生命值之前该玩家的分数会为0。不可通过指令修改。 xp:玩家经验值,不可通过指令修改。 level:玩家经验等级(注意和xp准则区分),不可通过指令修改。 food:玩家饱和度,和health准则一样,在玩家第一次刷新饱和度之前该玩家的分数会为0,不可通过指令修改。 air:玩家空气值(就是潜水时显示的那个),不可通过指令修改。 armor:玩家盔甲值,和health准则一样,在玩家第一次刷新盔甲值之前该玩家的分数会为0,不可通过指令修改。 复合准则可以自定义,其格式如下: <基础准则id:命名空间>:<次级准则>(1.12更新后) 复合准则实际上就是mojang将你菜单界面中的“统计数据”和计分板绑定在一起而已。基础准则具体有: teamkill.<队伍颜色>——玩家杀死指定颜色的队伍成员便会增加分数 killedbyteam.<队伍颜色>——玩家被指定颜色的队伍成员杀死便会增加分数 minecraft.custom:——对应的是统计信息菜单中的“通用”一栏信息。比如准则minecraft.custom:minecraft.leave_game就是跟踪每一名玩家统计菜单中的“游戏退出次数”。具体的每项统计信息所对应的命名空间id就太多了,需要的可以自行到minecraft wiki查看(指明路线:统计信息→命名空间id→统计信息列表)。 minecraft.picked_up:<物品id>——玩家捡起指定物品时便会增加分数(对应统计菜单“物品”一栏的“拾起个数”) minecraft.dropped:<物品id>——玩家丢弃指定物品时便会增加分数(对应统计菜单“物品”一栏的“丢弃个数”) minecraft.used:<物品id>——玩家使用指定物品时便会增加分数(对应统计菜单“物品”一栏的“使用次数”) minecraft.broken:<物品id>——玩家消耗指定物品时便会增加分数(对应统计菜单“物品”一栏的“工具消耗数”) minecraft.crafted:<物品id>——玩家合成指定物品时便会增加分数(对应统计菜单“物品”一栏的“合成次数”) minecraft.mined:<方块id>——玩家挖掘指定方块时便会增加分数(对应统计菜单“方块”一栏的“开采次数”) minecraft.killed:<实体id>——玩家击杀指定实体时便会增加分数(对应统计菜单“生物”一栏的“你杀死了n只xxx”中的n) minecraft.killed_by:<实体id>——玩家被指定实体击杀时便会增加分数(对应统计菜单“生物”一栏的“xxx杀死了你n次”中的n) 注意:java1.13更新中将统计信息中的“方块”并到“物品”一栏。 现在,我们有了一个计分项。但如果你想要修改显示名称该怎么办? 在基岩版和java1.13以下版本中,你只能删了重新搞。这时候你就需要使用remove: \/scoreboard objectives remove coin 这样子就可以删掉叫做coin的计分项。 但如果你忘记了计分项的名称该怎么办?使用list列出所有计分项以查看: \/scoreboard objectives list (注意,在java1.12.2以上版本中,如果你的计分项设置了显示名称,那么list只会列出该计分项的显示名称,要查看具体的名称需要将鼠标移到列出的计分项显示名称的上方) 在java1.12.2以上版本中,有一种便捷的方法可以不删除计分项就可以更改显示名称:modify。 举个例子:假设你想要修改我们刚才创建的coin计分项的名称为“软妹币”,你就需要执行: \/scoreboard objectives modify coin disyname “软妹币“ modify不只是可以修改名称,它还可以修改计分项中玩家分数的值的显示方式。 当然在研究这个值显示方式之前,我们得了解一下setdisy的作用。 上面列格式时就已经提到过setdisy的作用了:显示计分项于某个位置。 具体的这个位置有哪些呢? list——java版中是在tab玩家列表中显示每名玩家的分数(不显示具体是哪个计分项),基岩版中是在暂停界面显示。 sidebar——在屏幕的右侧显示列表,并在列表的最上方显示该计分项的显示名称 sidebar.team.<队伍颜色>——和sidebar作用相同,只是只会给指定颜色的队伍查看[仅java版] belowname——在玩家的头上面显示该玩家的分数 举个例子: \/scoreboard objectives setdisy sidebar coin 执行指令,就可以将我们刚才创建的coin计分项以列表的形式显示在右侧。需要注意,如果已经有其他计分项显示在该位置,执行该条指令后将会覆盖显示为coin计分项。 在基岩版,使用list和sidebar位置时还可以指定列表排序方式:ascending(从小到大)和descending(从大到小[默认])。比如: \/scoreboard objectives setdisy sidebar coin ascending 就可以将最穷的玩家显示在列表最上方的位置。 如果你仔细看了setdisy的格式,你会发现“计分项名称”这个参数是选填的。那如果不填会发生什么? 重置该位置,也就是取消显示计分项在该位置。比如: \/scoreboard objectives setdisy sidebar 就可以让右侧一栏重回清净。 通过modify的rendertype我们还可以修改指定计分项的分数显示时的样子。mojang给了我们两个选择:hearts(生命值)和integer(数值)。 比如: \/scoreboard objectives modify coin rendertype hearts 就会将coin计分项中每名玩家的分数以生命值的形式显示出来。 需要注意的是,生命值形式仅支持tab玩家列表。 ....... ....... ....... 在java1.13更新前,计分项的复合准则并不是这样,而是: <一级准则>.<二级准则>.[次一级准则].[次二级准则](1.13更新前) 复合准则也并不是完全和统计菜单的数据绑定。在1.13更新前,复合准则具体有如下内容: achievement.<成就id>——(1.12版本中被移除)以一个玩家达成指定成就数量作为值。比如achievement.diamonds就是“钻石”成就的达成次数。这个成就的达成次数是什么意思呢?举个例子,你获得到1块钻石,就达成了“钻石”成就1次。如果你再次获得一块钻石,虽然游戏不会告诉你你又一次达成了“钻石”成就,但是你实打实地达成了这个成就两次。由于minecraft wiki会慢慢舍弃旧游戏内容,我就把成就id全放这了,具体指的是什么成就自己扔进生草机里翻译:“acquireiron“、“bakecake“、“zerod“、“bookcase“、“breedcow“、“buildbetterpickaxe“、“buildfurnace“、“buildhoe“、“buildpickaxe“、“buildsword“、“buildworkbench“、“cookfish“、“diamonds“、“diamondstoyou“、“enchantments“、“exploreallbiomes“、“flypig“、“fullbeacon“、“ghast“、“killcow“、“killenemy“、“killwither“、“makebread“、“minewood“、“onarail“、“openinventory“、“overkill“、“overpowered“、“portal“、“potion“、“snipeskeleton“、“spawnwither“、“theend“、“theend2“。 stat.<内容>——对应1.13更新后的“minecraft.custom:”。比如stat.sneaktime准则就是玩家的潜行时间。“内容”可以填“animalsbred“、“armorcleaned“、“bannercleaned“、“beaconinteraction“、“boatonecm“、“brewingstandinteraction“、“cakesliceseaten“、“cauldronfilled“、“cauldronused“、“chestopened“、“climbonecm“、“craftingtableinteraction“、“crouchonecm“、“damagedealt“、“damagetaken“、“deaths“、“dispenserinspected“、“diveonecm“、“drop“、“dropperinspected“、“enderchestopened“、“fallonecm“、“fishcaught“、“flowerpotted“、“flyonecm“、“furnaceinteraction“、“hopperinspected“、“horseonecm“、“itemenchanted“、“jump“、“junkfished“、“leavegame“、“minecartonecm“、“mobkills“、“noteblockyed“、“noteblocktuned“、“pigonecm“、“yerkills“、“yoneminute“、“recordyed“、“sneaktime“、“sprintonecm“、“swimonecm“、“talkedtoviger“、“timesincedeath“、“tradedwithviger“、“trappedchesttriggered“、“treasurefished“和“walkonecm“。 stat.craftitem.<物品数字id或英文id>——对应1.13更新后的minecraft.crafted:<物品id>。如stat.craftitem.261准则就是玩家合成弓的次数,stat.craftitem.minecraft.bow也是玩家合成弓的次数。注意,使用英文id,命名空间就需要作为次1级准则,物品id就要放到次2级准则中。 stat.useitem.<物品数字id或英文id>——对应1.13更新后的minecraft.used:<物品id>,用法和stat.craftitem.<物品数字id或英文id>一样。 stat.breakitem.<物品数字id或英文id>——对应1.13更新后的minecraft.broken:<物品id>,用法也一样。 stat.mineblock.<方块数字id或英文id>——对应1.13更新后的minecraft.mined:<方块id>,用法仍然一样。 stat.killentity.<实体id>——对应1.13更新后的minecraft.killed:<实体id>。只不过支持的实体id相比于1.13更新后的版本要少许多,并且不支持mod实体,因为没有命名空间。如stat.killentity.viger就是杀死村民的次数。 stat.entitykilledby.<实体id>——对应1.13更新后的minecraft.killed_by:<实体id>,用法和stat.killentity.<实体id>一样。 需要注意,在java1.8版本之前,stat.craftitem等准则是不支持物品和方块的id名(英文id)的。 本章到此结束。 第四十二章 players——管理变量(分数) 在上一章,我们了解了如何管理一个计分项。在一个计分项中存在有多个玩家(或非玩家),每个玩家(或非玩家)都有一个属于自己的变量(分数)。那么我们该如何管理这些变量(分数)呢? 这就需要用到scoreboard的yers子命令,即\/scoreboard yers ... \/scoreboard yers 作用:控制记分板上计分项的变量(分数) 格式: \/scoreboard yers ... ... add <目标选择器><计分项><增加的分数>[nbt(仅java1.13之前)]——将所选玩家(或非玩家)在指定计分项中的分数增加指定值 ... remove <目标选择器><计分项><减少的分数>[nbt(仅java1.13之前)]——将所选玩家(或非玩家)在指定计分项中的分数减少指定值 ... set <目标选择器><计分项><分数>[nbt(仅java1.13之前))]——将所选玩家(或非玩家)在指定计分项中的分数设置为指定值 ... reset <目标选择器>[计分项]——将所选玩家(或非玩家)在记分板上的全部数据(或指定计分项上的数据)完全清除(注意不是清零,而是清除)。目标选择器可用*代指所有玩家和非玩家。 ... list [目标选择器]——列出所有正在被记分板追踪的玩家(或非玩家)。如果指定了玩家(或非玩家),那么将会列出选取的玩家(或非玩家)们在记分板上的所有数据。 ... get <目标选择器><计分项>——[仅java1.13及以上版本]获取指定单个玩家(或非玩家)在指定计分项上的分数 ... test <目标选择器><计分项><最小值>[<最大值>]——[仅java1.12.2及之前和基岩版]检测所选玩家(或非玩家)在指定计分项的分数是否大于等于最小值并且小于等于最大值。最小值和最大值均可使用*来代指-(最小值使用*)或(最大值使用*或不填)。 ... operation <目标选择器1><运算计分项1><操作><目标选择器2><运算计分项2>——将目标选择器1参数中所选玩家(或非玩家)的指定计分项的分数与目标选择器2参数中所选玩家(或非玩家)的指定计分项的分数进行一些操作 ... enable <目标选择器><触发器类计分项>——[仅java版]允许所选玩家(或非玩家)对指定触发器类计分项使用一次\/trigger指令。 ... random <目标选择器><计分项><最小值><最大值>——[仅基岩版]将所选玩家(或非玩家)的指定计分项分数随机设置为设定范围内的任何整数值。 通过yers子命令,我们可以set(设置)、add(添加)、remove(删除)、list(列出)、get(获取)、reset(重置)、operation(操作)、test(检测)、random(随机)和enable(触发器)。这些东西的内容很多,我们今天就只研究基本的,也就是上面我们提出的问题:如何管理变量(分数)。 管理变量,就得先有变量,不然管理啥呢?我们知道,一个玩家(或非玩家)被一个计分项计入后最多只能有一个属于自己的变量(分数)。而一个计分项创建之初是什么也没有计入的,也就是说这个计分项没有一个变量,空空如也。 为了给这个计分项添加一个变量,也就是计入一个玩家(或非玩家),我们就需要用到add这个子命令: ... add <目标选择器><计分项><增加的分数>[nbt(仅java1.13之前)] 增加的分数至少为0。当然,就算为0,这也算是计入该计分项了。 实际上,使用remove、operation和set也可以达到同样的计入效果。 比如,你要把你自己计入到“金钱”计分项中,就需要: \/scoreboard yers add\/remove\/set @s 金钱 0 如果你将一个还未计入“金钱”计分项的玩家的分数增加5会怎样? 其实不会怎么样。正如正常人的一般思维,刚刚计入计分项的玩家(或非玩家)其分数是从0开始算起。也就是说,给那名玩家添加5金钱实际上会先让他计入该计分项,此时他的分数为0,然后再将他的分数+5变成5。 这里的“金钱”计分项是作者自己编的,你想要运行上面的例子就得先自己创建一个叫金钱的计分项。 计入之后,我们该如何减少分数呢?这就要用到remove(删除): ... remove <目标选择器><计分项><减少的分数>[nbt(仅java1.13之前)] 比如我想要将玩家“张三666”在“金钱”计分项中的分数减少10,这就需要执行: \/scoreboard yers remove 张三666 金钱 10 假设他原本的分数是3。执行该指令过后,他的分数就变为了-7。 需要注意。记分板的分数其值是个int整形类变量,也就是其值的范围只能是-~。如果一个玩家的分数已经是-,你再减去个1,他的分数就会变为。关于为什么会这样,以及int整形究竟是个什么,你以后就会了解到。 如果你对此很感兴趣,那么你可以跳到后面135~140章尝试你是否能够理解。 分数可以增加和减少,当然也可以快速设定为指定的值。这时候就要用到set: ... set <目标选择器><计分项><分数>[nbt(仅java1.13之前)] 设置成功后,该变量的数将会变成设置的分数。比如我想要将“张三666”的“金钱”设为2,就可以: \/scoreboard yers set 张三666 金钱 2 你可能注意到了,在本章开头列出的格式中,还有一个reset(重置)。这个reset可和set没多大关系,因为reset是重置(更准确的说是清除数据)。其格式如下: ... reset <目标选择器>[计分项] 举个例子,假设我们运行了下面的指令: \/scoreboard yers reset 张三666 你就会惊奇地发现“张三666”的名字从右边侧栏的“金钱排行榜”中消失了。这并不是说他被挤出了该排行榜,或是他的分数被重置为了0,而是他的所有在记分板上的数据全部没掉并且记分板也不再跟踪他,直到他重新计入到某个计分项中。 这哪里是reset啊,这简直是clear啊! 如果你不信,你可以试试\/scoreboard list 张三666(列出张三666在记分板上的数据)或\/scoreboard get 张三666(获取张三666的分数),看看你能不能再次找到他的数据。 这确实太狠了。如果你只想clear掉他在“金钱”计分项中的数据,在“张三666”后面加上“金钱”即可,即:\/scoreboard yers reset 张三666 金钱 (实际上还可以更狠。目标选择器使用*可以代指所有正在被追踪的目标,也就是说\/scoreboard yers reset *可以完全清除整个记分板上所有玩家和非玩家的数据) 你现在可以尝试弄一个你自己的虚拟货币用于服务器中。 这个货币的名称自己想。作者想的是:$。 没错,名字允许你填$等符号。我们就以这个符号为名字举例子,输入并运行下面的指令: \/scoreboard objectives add $ dummy §a$ (java版: \/scoreboard objectives add $ dummy {“text“:“$“,“color“:“yellow“}) 你就成功创建了一个叫做$的虚拟货币! 作者现在没钱,所以作者我要给自己钱: \/scoreboard yers add @s $ ok,现在作者有100万美元了!(当然是游戏里)。 现在你可以尝试做一个记分板商店。我们运用clear指令和scoreboard指令结合即可建成一个收购商店(使用物品换取虚拟币)。而使用scoreboard和give指令可以建成一个用虚拟币购买实物的商店。 但是,计分项的分数可以是负数!我们既然要搞虚拟货币,就要防止这种负数欠账的事情发生。 此时,test子命令就派上用场了! 第四十三章 players——记分板商店 test,之前见过,意为“探测”、“检测”。通过test,可以探测一个变量的分数是否在一个区间内。我们就得通过它,来防止欠账的事情发生。 (注意,test子命令在java1.13更新中被移除。现在仅java1.12.2及以下版本和基岩版拥有该子命令) 现在已经有了“$”这个货币,并且作者有100万$(游戏里)。假设现在有一个物品,价值120万$(什么东东这么贵)。如果这个记分板商店就是一个scoreboard—yers—remove加上\/give,那么作者也会买成功,但是$变成了-20万$(欠了20万美元)。 但是,minecraft里可没有自带还债机制,所以作者能够一直扣下去。 为了防止这种事情的发生,我们就需要用到test子命令。其格式是: ... test <目标选择器><计分项><最小值>[<最大值>] 注意,在java版有test的时候,格式确实如上,“最大值”参数是选填的。但在基岩版中,“最大值”参数是必填的。 假设我们要使用test检测玩家“李四250”是否能够购买这个120万美元的东西,我们就需要执行指令: \/scoreboard yers test 李四250 $ * 其中,最大值被替换为了星号。这个“星号”是什么意思呢? 当最小值填*时,代指-;当最大值填*时,代指。 也就是说,这个\/scoreboard yers test 李四250 $ *,实际上是\/scoreboard yers test 李四250 $ 。 所以这条指令的意思是: 检测玩家“李四250”在$计分项上的分数是否大于等于(并小于)。 如果成功,那么游戏会提示“分数xxx在到范围内”。 如果失败,则会在“在”字前加个“不”字,并将整个消息的颜色改为红色。 在命令方块中检测成功也会输出信号,进而激活接下来的命令方块。 我们记分板商店的原理之一就是这个。命令方块如下摆放即可做成简单的记分板商店: a→b→c a(脉冲,不受制约\/无条件,红石控制\/需要红石): \/scoreboard yers test @p $<物品单价>* b(连锁,条件制约\/有条件的,保持开启\/始终活动): \/scoreboard yers remove @p $<物品单价> c(连锁,条件制约\/有条件的,保持开启\/始终活动): \/give @p <物品id> 1 这是最简单的记分板商店,其购买流程如下: 玩家按下拉杆激活a→a执行指令,检测玩家是否能够购买→如果能,激活b\/如果不能,结束购买→b执行指令,扣除玩家虚拟币,并激活c→c执行指令,给予物品给玩家→购买成功 这种记分板商店还有许多待完善之处: 1由于使用@p选取最近玩家,b和c可能将指令执行到错误的玩家上 2远处的玩家也可以碰到拉杆,但命令方块可能不会将指令执行到该玩家身上 3成功和失败都没有消息提示 解决办法也很简单: 一、目标选择器加上x、y、z参数指定执行中心,加上r或dx、dy、dz指定执行范围。 二、将每个购买项目单独做成一间1x1的铁门间,门内放测重压力板(如有装mod,可以使用夸克模组内的黑曜石压力板,更加安全)。 三、可以在a前面再加上两个命令方块d和e,在c后面加上f,即d→e→a→b→c→f。把a改为连锁,不受制约\/无条件,保持开启\/始终活动。d、e和f如下: d(脉冲,不受制约\/无条件,红石控制\/需要红石): \/scoreboard yers test @p $*<物品单价-1> e(连锁,条件制约\/有条件的,保持开启\/始终活动): \/tellraw @p {“text“:“购买失败“,“color“:“red“} f(连锁,条件制约\/有条件的,保持开启\/始终活动): \/tellraw @p {“text“:“购买成功“,“color“:“green“} 其原理就是在检测检测玩家是否能够购买前检测玩家是否不能购买。如果确实不能,发出消息“购买失败”。以及在玩家购买成功后发送“购买成功”的消息。 注意,在这里,d和e不能放在a、b、c、f之后,即不能: a→b→c→f→d→e 这主要是因为这是就变成了在检测玩家是否能购买后再检测一遍是否不能购买。不要小看这一前一后的问题,如果这名玩家能购买,购买成功后就不能再购买一个了,那么这个商店就会先后发出“购买成功”、“购买失败”两条消息。 现在,你知道如何做一个最基础的记分板商店了吧?这东西在网易租贷服中可大有用处。(毕竟网易租贷服可加不了什么mod或插件,只能靠指令) 记分板简要历史: java 1.5——加入了记分板 1.7.2——计分项的准则现在可以使用统计菜单中的数据了 1.8——现在非玩家也能被记分板追踪并拥有分数了;为yers下的reset子命令加入了“计分项”参数;统计类准则可以使用id名了;加入了队伍击杀相关准则以及其他的一堆准则;为yers下的add、set和remove子命令加入了nbt参数;为operation加入了=、>、<和><操作。 1.8.2——又加入了一堆准则 1.9——加入了stat.sneaktime、xp、food、armor、level和air等准则。 1.13——准则大改;加入了\/scoreboard objectives modify子命令。 基岩版 1.7.0——加入了被阉割的记分板和dummy准则。 第四十四章 在minecraft用指令算1+1=? (注意:这一章很烧脑,建议在空闲时间大脑容量充足时阅读,最好阅读时在游戏内实地操作) 我们知道,记分板中所计入的玩家分数都是变量。既然是变量,那么多个变量是否可以互相运算呢? 答案当然是可以。mojang也为这个运算功能单独提供了一个子命令:operation(操作) operation的格式如下: \/scoreboard yers operation <被跟踪的玩家或非玩家a:目标选择器><计分项a><计算方式><被跟踪的玩家或非玩家b:目标选择器><计分项b> 看着是不是有点迷糊?简单来说,使用operation子命令的具体运算过程是这样的: 第一步:使用目标选择器指定目标a 第二步:指定计分项甲 (上面两步相当于将目标 a在计分项甲中的分数作为输入a。比如,假设目标a是张三,计分项甲是dummy型的“违法次数”,张三的违法次数是12,那么输入a的值就是张三的违法次数的值,即a=12。) 第三步:指定计算方式(或者说是指定操作) 第四步:使用目标选择器指定目标b 第五步:指定计分项乙 (上面的四、五步和一、二步同理,将目标 b在计分项乙中的分数作为输入b) 第六步:将输入a和输入b两个量按照指定的操作进行运算。 第七步:按照指定的操作更改输入a的和输入b的值。(大部分操作只会更改输入a的值,即把运算得出的值覆盖原本输入a的值) 举一个简单的例子: \/scoreboard yers operation 张三 gold +=李四 gold 假设张三在gold计分项中的分数是1,李四也一样。那么这串指令运行过后张三在gold计分项中的分数将会变成2(1+1),但李四的分数还是1。 这个例子中,采用的操作(运算方式)是+=,即“求和”。具体是将输入a(张三的gold分数)和输入b(李四的gold分数)相加,得到结果c,并将结果c的值覆盖原本输入a的值。也就是说,这个“求和”是这么算的: 输入a =结果c =输入a +输入b (注意,这不是正常的数学等式。在这里有一个运算的时间先后。即最左边的输入a是运算完成时的输入a,并不等于最右边刚开始运算时“输入a+输入b”中的输入a,两者是一新一旧,不能将它们认为是同一个“输入a”) 操作不止有求和(+=),它一共有九种: (注:“??”指向下取整。如?3.12?=3,?-4.82?=-5) +=——求和 -=——求差(输入a =结果c =输入a -输入b) (如:2 -= 1 ,结果就是2-1=1) *=——求积(输入a =结果c =输入a x输入b) (如:2 *= 3,结果就是2x3=6) \/=——求商(输入a =结果c =?输入a ÷输入b?) (如:24 \/= 12,结果就是24÷12=2;17 \/= 13,结果就是?17÷13?=1) %=——求余(输入a =结果c =输入a mod 输入b =输入a -?输入a ÷输入b?x输入b。简单点的说法就是:输入a =(输入a ÷输入b)的余数) [注:java1.13.1版本更新中,%=的内部代码运算采用的某个方法从原本的%改成了math.floormod。不知道这会造成什么影响。我尚未在1.13.1和以上版本中进行相关实验。] (如:17 \/= 13,结果就是17-?17÷13?x13=17-1x13=17-13=4) =——赋值(输入a =结果c =输入b。即把输入b的值覆盖到输入a上)[注:java1.8以下版本没有] (如:15 = 6,结果就是6) <——取较小值(如果输入a ≥输入b ,输入a =结果c =输入b;如果输入a ≤输入b,输入a =结果c =输入a)[注:java1.8以下版本没有] (如:17 < 13 ,结果就是13) >——取较大值(如果输入a ≥输入b ,输入a =结果c =输入a;如果输入a ≤输入b,输入a =结果c =输入b)[注:java1.8以下版本没有] (如:13 > 17 ,结果就是17) ><——互相交换值(输入a 和输入b值互换)[注:java1.8以下版本没有] (如 4 >< 19,结果是“输入a=19,输入b=4”) 这似乎有点烧脑?没关系,下面还有更烧脑的。operation实际上是个很复杂的东西,将其了解透后你的逻辑运算能力应该能变强几分。 我们知道,目标选择器可以选择多个目标。而你有没有注意到,刚才我们所了解的不过都是输入a和输入b均都为1个的情况。那么如果输入a有多个,或是输入b有多个,甚至是输入a和输入b都有多个的时候,operation又会怎样运算? 由于接下来的内容minecraft wiki并未记载(注:英文minecraft wiki有两行记载,但讲得过于简略),网上也搜不到相关内容,下面内容都是作者在java1.12.2版本中实验得出的。如果你对此很感兴趣,你也可以自己尝试去做做实验,看看在其他版本下或其他情况下结果是否一样。 1当输入a有多个分数,而输入b仅有一个分数时 现在我们假设输入a有三个: a?=1 a?=0 a?=-1 输入b有一个: b=3 我们对这三个输入a和输入b进行+=(求和)操作,最终得出来结果是: a?=c?=a?+b=1+3=4 a?=c?=a?+b=0+3=3 a?=c?=a?+b=-1+3=2 因此不难发现,当有多个输入a但只有一个输入b时,游戏将会把每个输入a均与输入b进行一次运算操作。 (注:这不是真正的实验过程,这已经被大大简化了) 2当输入a有一个分数,而输入b有多个分数时 我们假设输入a=1,输入b有三个: b?=2 b?=3 b?=-4 我们对这个输入a和三个输入b进行+=操作,最终得出结果是: a=c=a+b?+b?+b?=1+2+3+(-4)=2 不难发现,当输入a只有一个但输入b有多个时,输入a将与每个输入b都进行一次运算操作,再把最终得出的结果覆盖到原本的输入a上。 3当输入a和输入b均为多个分数时(该情况minecraft wiki并未记载): 我们假设输入a有两个: a?=1 a?=0 输入b也有两个: b?=3 b?=-2 我们也对它们进行+=操作,最终得出的结果竟然是: a?=c?=a?+b?=1+3=4 a?=c?=a?+b?=0+3=3 没错!输入a和输入b多个的情况下,游戏只会选择一个输入b来参与运算。也就是说,在其他条件相同的情况下,该结果跟输入a多个但输入b只有一个的结果一模一样。 这应该算是个bug吧...... 对了,既然游戏只会选择一个输入b来参与运算,那么这个输入b会选择谁呢? 根据作者的测试,游戏会选择目标选择器排列的第一个输入b,这时候就要看你用的目标选择器。如果用的是@p、@e、@a,就是就近原则;如果是@r,则是随机。 这个排列顺序在operation中不只是用于选择输入b,它还用于在情况1下决定输入a们与输入b运算的先后顺序和情况2中决定输入a和哪些输入b先运算,哪些输入b后运算。 了解这些后,我们就可以来看一种升级版的情况1: 当输入a有多个,输入b有一个且这个输入b也是一个输入a时 这个情况是啥意思呢?简单来说,现在有张三李四王五,我们拿他们三的分数作为三个输入a,并把张三的分数也作为输入b。是不是复杂了起来? 我们假设有三个输入a,分别是: a?=-2 a?=1 a?=3 (按照下标数字从小到大参与运算) 而输入b就是a?。 我们对它们两按照该情况进行+=运算,最终得出来以下结果: a????=c?=a????+a????=-2+1=-1 a????=c?=a????+a????=1+1=2 a????=c?=a????+a????=3+2=5 上面两个式子中,为了让大家方便理解,我特别标上了old(旧)和new(新)来代表未运算和已运算的两个不同的量。 不难发现,当输入a有多个,并且输入b是众多输入a中的一个时,如果某个输入a与输入b运算时这个输入b所关系的输入a还没有运算,那么这个输入a将会与旧的输入b进行运算;如果某个输入a与输入b运算时这个输入b所关系的输入a已运算完成,那么这个输入a将会与新的输入b进行运算。 这读起来有点绕口啊。没关系,虽然现在你不一定看得懂,但只要你在游戏中实地做过实验你估计就懂了。 本章就到这里......了? 刚才的四个探究中,我们都在探究operation在有多个输入和多个输出情况下会如何计算。一般来说,进行这种研究会用到命令方块。你知道的,命令方块运行指令成功后会输出结果,这个结果可能会影响到命令方块输出的红石信号强度。比如我们之前讲到的testfor指令,探测到有多少个实体就输出多强红石信号。 那么operation在命令方块中执行成功是否会影响到命令方块输出的红石信号强度呢? 答案是:能! 经过作者的测试,operation运行一次输出的红石信号强度,等于该次operation计算的次数。比如情况1中,如果指令是在命令方块中运行,那么运行成功后命令方块将输出3级红石信号,因为operation运算了3次。情况2输出的信号也一样,别看作者给出的只是一行式子,但是operation仍然确确实实运算了3次。 这是一个冷门到极致的知识,冷门到连minecraft wiki也没有记载。当然我也不确定在新版本是否还有这个功能,也许已经被移除了呢? 新年好! \/title @a [type =书友] title §c新年快乐! 各位书友们新年好! 虽然说昨天晚上停电,没能及时给大家问好,但是我至少现在也补回来了吧。(话说春晚还没看呢)。 那么在此祝贺各位在新的一年里大吉大利、财源滚滚、红包暴涨、作业爆减、运气爆发。 祝贺各位属鼠的书友在新的一年里吉祥如意,幸福美满。 但是大家还是要小心武汉的病毒啊,听说已经传到法国、新加坡等地了。出门在外要小心,就算宅在家里玩游戏,最好也不要出去人多的地方,以及疫情很严重的地方。在这里祝贺大家百病不侵、身体健康。 这里也谢谢各位的推荐票,有了它我就知道有人在看我的书,就有继续更的动力。我把这个动力称作:有推荐票就去肝的动力。 (我的天外面的雨下得真大)所以这一章不算是一个正经的章节就到这了,感谢大家,最后祝大家在新的一年里快快乐乐,健健康康。2020鼠年快乐! 第四十五章 变量的几种常用用途(破百收藏纪念) 在研究用途之前,yers还有两个子命令没讲:enable和random。 enable是“触发器”。关于触发器,还要关系到\/trigger指令。关于这个东西就要到第九十八章了。 random是“随机”,也就是把选定的一个或多个变量设为指定范围内随机值。它的格式是: ... random <目标选择器><计分项><最小值><最大值> 举个例子: \/scoreboard yers random @a luck -500,500 (注:逗号仅区分两个数字之用,实际使用时不需要加逗号) 这个指令的用处是将所有在线玩家在luck计分项中的分数设为从-500到500间的任意数(包括-500和500)。 接下来就是正片了。 第一种:自定布尔值 之前提到过,布尔值是:false和true,即错和对。有些时候是用二进制数来表达(1和0)。 既然可以使用数字,那么也就是说变量也可以像布尔值那样表达。即: 1——对、有 0——错、没有 这样子可以用来判断一些事情,比如判断有个人是否是vip,如果它的vip值为1,那么即它是vip;反之,那么他就不是vip。还有,这可以配合触发器和\/tellraw的json文本来制作一些文本按钮。 这样子可以用于一些一次性物品,刚才的vip就是一个例子。 这也可以用于自定权限。比如是1,那么这个人就是管理员;如果是0,那么这个人就不是管理员。 当然,也可以跳出1和0,比如可以自定游客(2)、成员(0)、腐竹(1)和协管(3)。 (实际上如果自己开个java服务器设定权限也不需要这么搞,装个权限插件搞几个权限组就行了) 第二种:自定计时器 手机里的秒表和计时器都是很重要的。但是,使用命令方块也可以自定计时器。 这里,我们必须记得:命令方块1秒钟在正常情况下运行20次。 我们可以使用test加上scoreboard-yers-remove就可以弄一个计时器。 首先,用set设置变量的值,即倒计时多久。由于命令方块1秒运行20次,所以秒数乘20等于变量的值(算术差的各位拿起计算器算算)。 然后是test,即: \/scoreboard yers test <变量名><计分项> 1 注意,test必须为重复执行,而且必须在remove运行前。 remove填: \/scoreboard yers remove <变量名><计分项> 1 这样子,每秒减20。如果设置为1200,1200除20等于60,即60秒后才会停止。 你也可以在旁边再弄一个到点时自动广播,然后再重新设为1200,做个全自动的循环装置。 当然,你要红石循环也可以,但那样子安全性不高。一个熊过来就玩完了。 也可以反过来,即test检测到哪个数就停止。add一直加1,每秒加20。这样子,test放的数就是秒数。 第三种:数字货币 这个很常用,现在很多私人服务器都是很流行这种的。为何?数字货币相对于实体货币有很多优势: 1.安全性高。实体货币可以通过bug刷取,数字货币无实物,不可通过bug刷。 2.隐私性高。实体货币容易被熊孩子偷走,数字货币不可被偷。 3.不易销毁。实体货币丢个岩浆就玩完了,tnt、苦力怕一炸就没了。数字货币无实体,不容易销毁(除非获得管理权限)。 但是,实体货币也是有一点优势的:方便交易。所以,最好就是: 1.防止刷物品,禁止熊孩子的出现,增强防作弊、防熊措施。 2.采用实体、数字货币互换,实体货币可以换成数字货币、数字货币可以换成实体货币。 3.增强服务器权限管理措施。 所以,这就是变量的几种常用用途。 另外说一下:本书破百收藏了! 第四十六章 team——管理队伍和成员 前面我们了解到,记分板的作用就是承载各个计分项。实际上,记分板的作用不止于此,在minecraft:java版中(严格来说是minecraft:java 1.13之前的版本)中,记分板还有一个极其重要的功能:游戏队伍(team)。 你是不是对记分板有“游戏队伍”这个功能感到不可思议?mojang也是这样想的,于是在minecraft java1.13扁平化中将这个功能从记分板中独立了出来,成了一套基本上独立的系统。 说了这么多,那么我们该如何使用这个功能呢? 其实不难。在minecraft:java1.13版本之前,该功能是内置在scoreboard指令中的,即teams子命令。通过team,我们可以:add(添加)、remove(删除)、list(列出)、join(加入)、empty(清除)、leave(离开)以及option(设置)。它的具体格式是: \/scoreboard teams ... \\\\队伍管理\\\\ ... add <队伍名称>[队伍显示名称]——添加队伍。 ... list [队伍名称]——列出当前所有队伍及其信息。如果指定了队伍名称,将会列出该队伍的成员名单。 ... remove <队伍名称>——删除队伍。 \\\\队伍成员管理\\\\ ... join <队伍名称>[目标选择器]——将所选目标加入到队伍中。目标选择器可用*代指所有玩家和非玩家。目标选择器未填写的话默认是执行者自己。(注:一个玩家或非玩家只能同时存在于一个队伍中,加入另外一个队伍将会自动退出原先的队伍) ... leave [目标选择器]——将所选目标从ta所在的队伍中移出。目标选择器可用*代指所有玩家和非玩家。目标选择器未填写的话默认是执行者自己。 ... empty <队伍名称>——删除指定队伍中的所有成员。 \\\\高级队伍管理\\\\ ... option <队伍名称> color <颜色>——设置队伍的颜色。 ... option <队伍名称> friendlyfire <布尔值:true|false>——设置队伍成员间是否可以互相伤害。默认为true,如果为false则不可以互相伤害。 ... option <队伍名称> seefriendlyinvisibles <布尔值:true|false>——设置该队伍的成员是否可以看见处于隐身状态的队友(如果设置为true会看见半透明的隐身状态队友,false则保持通常情况,即不可见)。默认为true。 ... option <队伍名称> nametagvisibility <名称牌可见性:never|hideforotherteams|hideforownteam|always>——设置该队伍成员头上名字(更准确的说是名称牌)的可见性,默认为always。 ... option <队伍名称> deathmessagevisibility <死亡信息可见性:never|hideforotherteams|hideforownteam|always>——设置该队伍成员死亡信息的可见性,默认为always。 ... option <队伍名称> collisionrule <碰撞模式:always|never|pushownteam|pushotherteams>——控制该队伍成员的碰撞模式,默认为always。 不难发现,队伍的组成和计分项的组成差不多。一个队伍的组成有如下几个部分: 1名称——除了这个是队伍的名称外,其他方面都与计分项的名称相同。 2显示名称——除了这个是队伍的显示名称外,其他方面都与计分项的显示名称相同。 3成员 4队伍颜色 5队伍规则 (实际上一个队伍还有前缀[prefix]和后缀[suffix],但是由于两者在1.13版本中才能在命令中被正式使用,这里我们先不了解。关于前后缀的内容,会在第一百一十九章讲到。) 现在,我们可以尝试自己创建一个队伍: \/scoreboard teams add team 一个队伍 运行这条指令,游戏将创建一个名称为team,显示名称为“一个队伍”的队伍。 如果你对这个队伍并不满意,就需要使用remove删除这个队伍: \/scoreboard teams remove team 这样子,就成功删除一个队伍了。 如果你是一条鱼,只有7秒记忆,创建后第10秒你想要删除这个队伍,但是你在3秒前已经忘记这个队伍叫什么了,此时你该怎么办? 运行\/scoreboard teams list可以列出所有队伍及其显示名称和成员数量。我们现在运行一遍,就会得到如下信息: 记分板上正在显示1个队伍: -team:''一个队伍''有0个玩家 list子命令还可以显示指定队伍的成员名单。当然,在了解并使用之前,我们不妨先来看看如何为一个队伍添加成员。 虽然游戏一直说是添加玩家,但是实际上队伍成员和计分项的分数持有者一样,可以是个实体甚至是不存在的玩家。添加成员需要用到join子命令。比如我们要将这存档中所有的羊(sheep)加入到刚刚我们创建的team队伍,就需要运行如下指令: \/scoreboard teams join team @e[type=sheep] 然后你就会看到一堆的实体uuid,这些都是羊们的uuid,而且现在这些羊都是这个队伍的队员了。如果你想要仔细看看这些羊的uuid,就需要使用list列出成员名单,具体指令如下: \/scoreboard teams list team 这将会列出team队伍的所有成员。 相应的,我们也可以使用leave子命令来让羊们都离开这个队伍: \/scoreboard teams leave @e[type=sheep] 运行上面的命令后,理想情况下team队伍就没有成员了。 需要注意一点,一个玩家或非玩家在同一个存档最多只能同时存在于一个队伍中。因此,如果我们还创建了一个队伍叫做duiwu,在没有使用leave子命令把这群羊从team队伍移出之前,我们运行\/scoreboard teams join duiwu @e[type=sheep]把这群羊加入到duiwu中,然后又一次运行\/scoreboard teams list列出team和duiwu的信息,你就会惊奇的发现在没有使用leave子命令的情况那些羊们竟然自动退出了team这个队伍,全跑到了duiwu这个队伍中。 因为这个原因,所以leave这个子命令才没有一个“队伍名称”参数,功能也不是退出指定队伍而是使所选目标离开其所在的队伍。 理想情况下,运行上面的join和leave子命令来对羊们进行队伍归属操作,是能做到全体操作的。但在现实中,有些羊可能会因为种种原因(如处于非加载区块中)而没有被目标选择器选中,导致它还在原本的队伍。如果只有一两只手抄一下uuid也没关系,但如果是五只、六只甚至是几十只呢?这时候你还会去抄吗? 其实你并不需要抄那些uuid,你只需要用一条指令即可: \/scoreboard teams empty team 运行后,队伍team中的所有成员就被清除掉了。这个empty子命令的作用就是这样,清除指定队伍中的所有成员。 上面的内容均是minecraft java1.13扁平化更新前的内容。那么1.13更新后呢? \/scoreboard teams被单独的指令\/team替代。好在,内容基本保持不变,\/team的格式和原本的teams子命令相差不大,唯一的一个重大改变是option(设置)子命令变成了modify(修饰)子命令,并且该子命令下面还多了两个东西:prefix(前缀)和suffix(后缀)。当然,关于前后缀的内容,我前面已经说过了,第119章有讲到。所以本章的内容还是可以套到目前的最新版本当中的。 (注:队伍显示名称的值在1.13及以上版本是json文本组件) 现在,我们已经知道了如何使用add、list、remove、join、leave和empty这六个子命令,本章也差不多可以到这里结束了。下一章我们来了解一些高级一点的操作。 team的历史: minecraft:java 1.5——在记分板的基础上加入了队伍相关功能 1.8——现在非玩家也可以加入队伍了(注意,1.8版本之前,仅玩家可以被计入记分板和加入队伍)。同时加入了队伍的相关准则、队伍侧边栏显示和nametagvisibility、deathmessagevisibility队伍规则。 1.9——加入了collisionrule规则。 1.13——以指令\/team替代了\/scoreboard teams,同时将option改为modify。加入了 prefix和suffix。并且,队伍显示名现在是json文本了。 第四十七章 team——队伍的颜色和规则 在上一章,我们了解到一个队伍是由“名称”、“显示名称”、“前缀和后缀”、“成员”、“队伍颜色”和“队伍规则”组成的。其中,队伍颜色和队伍规则是什么东西呢? 队伍颜色,顾名思义,就是一个队伍的颜色。一个队伍的颜色会体现在成员的头上、聊天栏、tab菜单和侧边栏的名字中。当一个队伍设置了颜色,它的成员的名字也就会使用该队伍的颜色(比如设置成绿色?)。 minecraft中一共有16种队伍颜色:ck(黑)、dark_blue(深蓝)、dark_green(深绿)、dark_aqua(深青)、dark_red(暗红)、dark_purple(暗紫)、gold(金)、gray(灰)、dark_gray(深灰)、blue(蓝)、green(绿)、aqua(青)、red(红)、light_purple(亮紫)、yellow(黄)和white(白)。(实际上还有一种:reset,即默认颜色。但这个颜色无法用于记分板侧边栏显示中,即并没有sidebar.team.reset这个侧边栏显示位置) 我们可以通过使用子命令option\/modify中的color来设置队伍颜色。比如我们想要设置队伍team为黄色,我们只需要运行: \/scoreboard teams option team color yellow (\/team modify team color yellow) 队伍的颜色实际上很有用。如果能妥善运用的话,或许能搞出类似于自定义npc mod内的中立方(黄色)、友好方(绿色)和敌对方(红色)。并且由于队伍颜色和记分板的侧边栏显示有关,如果能奉献几个肝,或许可以做出原版的起床战争,不用插件和mod的那种! 队伍的规则(注:这个不是官方说法,仅仅是作者为了方便你们理解而分的类)有五个: 1friendlyfire ... option\/modify <队伍名称> friendlyfire <布尔值:true|false> 这个规则控制队伍内的成员是否可以互相攻击,默认为true。如果为false,则队伍成员间无法伤害到对方。当然,仅仅对队伍内成员有效,不属于本队成员的人照样可以攻击本队成员,本队成员也可以照常攻击非本队成员。 2seefriendlyinvisibles ... option\/modify <队伍名称> seefriendlyinvisibles <布尔值:true|false> 这个规则控制队伍内成员是否可以看到其他处于隐身状态下的成员,默认为true。如果为true,本队成员就可以看到半透明的隐身本队成员;如果为false,则不能看到。当然,这个规则仍然仅对队伍内成员生效。 3nametagvisibility 该规则控制队伍内每个成员的名称牌(就是头上显示的名字)对其他人的可见性。该规则默认值是always,即公开显示,所有人都能看到。其他三个值如下(注:下面的例子中,张三和李四为红队,王五为蓝队。红队为本队,蓝队为他队。): never——私密,所有人(不管是本队的还是非本队的人)都看不见 (即王五和李四都无法看见张三的名字) hideforotherteams——即hide for other teams(向其他队伍隐藏)。仅有本队成员可以互相看到名称牌,他队成员无法看见。 (李四和张三可以互相看见对方名字,但王五无法看见李四和张三的名字) hideforownteam——即hide for own team(向本队隐藏)。仅其他队伍可以看见本队成员的名称牌,本队成员互相无法看见。 (李四和张三无法看见对方的名字,但王五可以看见李四和张三的名字) 4deathmessagevisibility 该规则控制队伍成员死亡信息的可见性,内容和nametagvisibility规则差不多。默认为always,即公开。其他三个还是never(私密)、hideforotherteams(向非本队成员隐藏)和hideforownteam(向本队成员隐藏)。 5collisionrule 该规则控制队伍成员与本队成员还有他队成员的碰撞情况。默认为always,即队伍内每个成员与任何实体都会发生碰撞。其他三个值分别是: never——队伍成员不会和任何玩家或生物发生碰撞 pushownteam——即push own team,只会与本队成员发生碰撞。 pushotherteams——即push other teams,只会与非本队成员发生碰撞。 妥善运用队伍规则,可以更好地做出一个小游戏而尽量甚至完全不借助插件。比如nametagvisibility用在迷宫当中就非常好。 本章就到这儿。 第四十八章 tag-标签 前面我们了解到,记分板的作用除了承载各个计分项,还有队伍功能。实际上,记分板不止是有这两个功能,它还有一个重要的功能:标签功能(tag)。 什么是标签?你在各大视频平台上发视频时,可以为视频添加标签,让大数据帮你把视频推给感兴趣的人看;你开启了各大网盘的相册备份功能,网盘备份好图片后还顺带帮你给各个图片和视频添加了标签以归类;你由于做错一件事情,被你的亲朋好友贴上一个不好的标签,这让你短期内不想见人......可以说,不管在现实中还是在网络上,标签都是随处可见并且极其有用的东西。 在minecraft中,标签的作用也和上述说的其他情况相差不是很大。你可以通过给实体添加各种标签来对实体进行分类。比如你要做一个小游戏,玩家可以选择不同职业。那么你就可以在一名玩家选定职业后,给该玩家一个该职业特有的标签,方便后面进行游戏时调用。 说了这么多,那么标签该如何使用呢? 相较于其他记分板的功能,标签的使用极其简单。在java1.12.2版本之前,标签的功能藏在scoreboard命令中yers子命令下的tag子命令,其格式如下: \/scoreboard yers tag <目标选择器>... ... add <标签>[nbt]——给选定的目标添加一个标签 ... list ——列出选定的目标所携带的标签 ... remove <标签>[nbt]——删除选定的目标所携带的指定标签 (注:上面的目标选择器可以使用*来代指所有正在被记分板追踪的目标) 在java1.13更新之后和基岩版中,标签功能有一个独立的指令:\/tag。tag的格式和原本藏在yers子命令下的tag差不多: \/tag <目标选择器> add <标签名>——给选定的目标添加一个标签 \/tag <目标选择器> remove <标签名>——列出选定的目标所携带的标签 \/tag <目标选择器> list ——删除选定的目标所携带的指定标签 (注:上面的三个目标选择器也可以使用*来代指所有正在被记分板追踪的目标) 是不是很简单?一个标签实际上就由一个标签名组成,存储在实体或玩家的nbt数据中。 但是简单归简单,还是要稍微讲一下的。 我们先尝试给自己上一个标签: \/tag @s add a_tag(适用于java1.13更新之后和基岩版) \/scoreboard yers tag @s add a_tag(适用于java1.13更新前) 需要注意,在java版中,标签名称必须遵循以下规则: 1只能由数字、字母、+、-和.组成 2不能有空格 在基岩版中,标签名称比较开放,但仍然有以下规则: 1可以由任意字符组成 2可以有空格。但有空格的标签必须使用英文半角引号包裹起来。比如:“a tag“。 现在我们自己有一个标签了。我们可以通过\/scoreboard yers tag @s list或\/tag @s list来列出我们身上的所有标签,也可以通过\/scoreboard yers tag @s remove a_tag或\/tag @s remove a_tag来删除该标签。 现在你知道如何使用标签了吧?当然,标签功能要发挥真正作用还需要目标选择器的配合。需要注意,在java版中,单个实体最高能有1024个标签,基岩版则无限制。 所以,下一章我们将学习目标选择器中的记分板功能! 历史: java 1.9——加入了tag标签功能 1.13——移除了\/scoreboard yers tag,以\/tag指令替代。 基岩版 1.9.0——加入了\/tag和tag标签功能 第四十九章 目标选择器中的记分板 网易我的世界手机版中,有一个租贷服在循环发布的服务器公告上写着如下信息: 你知道吗,在xxx服中,花费金币总量超过一定数额可以解锁更多特权! 花费金币总量超过5000,开放资源区2区 花费金币总量超过2万,开放跑酷地图-大日御舆 花费金币总量超过5万,开放主城-双料高级商店 ...... 更多相关信息请到主城大厅处查看 从指令方面研究这个信息,我们可以想到至少两种判定玩家是否拥有指定特权的方法: 1创建一个专门记录消费的计分项,每次玩家成功消费均增加该玩家在这个计分项上的分数。判定玩家是否拥有权限时都使用test子命令。 2创建一个专门记录消费的计分项,每次玩家成功消费均增加该玩家在这个计分项上的分数。准备一个重复执行的命令方块,每隔一段时间(或是在玩家消费完后检测一遍)给达到条件者添加特殊的tag标签。判定玩家是否拥有权限时,就根据该玩家是否拥有指定的标签来判定。 不管是第一种还是第二种方法,我们都是使用test子命令来判断玩家的分数是否达到了范围内。这样做明显效率会比较低下,而且不适用于java1.13更新后的版本。 而且,在第二种方法中,我们该如何判断一个玩家是否拥有指定标签呢?难不成用remove试着删除一下,看看能否成功并输出红石信号激活接下来的命令方块? 这两个技术问题其实很好解决:使用目标选择器中的记分板相关参数。 在目标选择器中,检测目标在指定计分项上的分数是否满足条件的参数是score(java1.13更新之前)和scores(java1.13更新后和基岩版)。 虽然两者仅仅差一个“s”,但用法大径相庭。 先来说说java1.13更新之前的score参数。这个score参数的用法如下: score_<计分项名称>=<最大值> score_<计分项名称>_min=<最小值> 和许多其他java1.13更新前的参数类似(如r和rm,范围最大值和范围最小值),score参数也被分成了max和min两个细分参数。举个简单的例子: \/give @a[score_coin=20,score_coin_min=15] diamond 这条指令的意思是:给予所有在coin计分项上的分数满足大于等于15并小于等于20的在线玩家一颗钻石。如果运行这条指令时,当前服务器有五个在线玩家:老张(coin为1)、老李(coin为15)、老黄(coin为18)、老刘(coin为20)和老邓(coin为27)。那么在运行这条指令之后,老李、老黄还有老刘将会得到一颗钻石,但是老邓和老张不会得到。 现在你明白如何使用score参数了吧? 再来说说scores参数。该参数和java1.13更新后的许多参数类似(如distance,采用典型的“两点区间法”以确定值范围)。其格式如下: scores={计分项a=值或范围,计分项b=值或范围......} 其中的“值或范围”,我们已经很熟悉了: 0..——大于等于5 ..2 ——小于等于2 0..2 ——大于等于5且小于等于2 1 ——等于1 举个例子: \/tag @a[scores={gamepoint=150..,killnumber=20..,dienumber=0..3}] add gold 这条指令的作用是:寻找gamepoint分数大于等于150,killnumber分数大于等于20且dienumber的分数大于等于0且小于等于3的所有玩家,给他们添加“gold”标签。 现在你也会用scores参数了吧?是不是很简单? 当然,目标选择器中的记分板相关参数不止这两个,还有另外两个参数: team(队伍)和tag(标签)。 这两个的使用就更简单了。和type还有name参数类似,它们的格式是: team=<队伍名>——选取属于指定队伍的目标 team=!<队伍名>——选取不属于指定队伍的目标 tag=<标签>——选取拥有指定标签的目标 tag=!<标签>——选取没有拥有指定标签的目标 举个例子: \/tp @a[team=yellow,tag=skywaryer]@e[type=armor_stand,name=yellowce,limit=1,sort=nearest] 这条指令的作用是:寻找属于队伍yellow且持有skywaryer标签的所有玩家,并将他们传送到距离执行地点最近的叫做yellowce的盔甲架处。 需要注意一点。在一个目标选择器中,只能有一个“team=指定队伍”。原因相信你是知道的:一个玩家或非玩家在同一时间同一存档的情况下最多只能在一个队伍中。因此,minecraft中是不会出现一个玩家同时在两个队伍中的情况。如果出现了,那就是bug(特性)! team、tag两个参数和type、name两个参数类似,但是也只是类似。由于队伍功能和标签功能的特殊性,并不是所有实体和玩家必须要属于一个队伍或挂着一个标签。那么如何选取那些不属于任何队伍或者是没有任何标签的玩家、实体呢?更进一步的话,如何选取所有有队伍归属或者是有标签的玩家、实体呢? 其实很简单。team和tag参数还有两个特殊格式: team=——选取所有无队伍归属的目标 team=!——选取所有有队伍归属的目标 tag=——选取所有没有标签的目标 tag=!——选取所有有任意标签的目标 是不是很特殊?我们来尝试用一用: \/spawnpoint @a[team=]~~~ 这条指令的作用是:选取所有无队伍归属的玩家,并将他们的出生点设置在指令执行处。 这就是记分板的所有基础内容了。本卷也到此结束。 第五十章 多人游戏指令 相信很多minecraft服务器的服主都很重视服务器的管理,因为一个服务器想要做大做强,管理方面就必须要做好。但要管理一个minecraft服务器绝非易事,就算这个服务器是网易的租贷服,仍然有很多需要去解决的问题: 1.如何防熊和防作弊。 2.如何制定和实施服务器规则。 3.如何安排好管理层,尽量保证玩家有问题管理员可以随时解决。 ...... 而如果这个服务器是自行搭建的第三方服务器,那问题就更多了: 1.如何抵挡住ddos等对服务器的攻击。 2.如何防止服务器被他人注入木马。 3.如何解决一些服务器的bug、恶性漏洞。 ...... mojang官方也在他们的minecraft原版服务端中提供了一些特殊指令,方便服主管理服务器。这些指令由于比较特别,只能在多人游戏中甚至是服务器中使用,所以我们把这些指令统称为:多人游戏指令。 多人游戏指令,顾名思义就是在多人游戏中使用的指令。这些指令不可在单人游戏模式中使用,只能在多人游戏模式和服务器中使用。当前版本(java和基岩1.18)的原版多人游戏指令有: \\\\黑名单管理[仅java版]\\\\ \/ban ——封禁某玩家名(将某玩家名加入黑名单) \/ban-ip ——封禁某ip地址(将某ip地址加入黑名单) \/banlist ——查看黑名单 \/pardon ——解封某玩家名(将某玩家名从黑名单中移除) \/pardon-ip ——解封某ip地址(将某ip地址从黑名单中移除) \\\\管理员管理\\\\ \/op ——赋予某玩家管理员(op)权限 \/deop ——撤销某玩家的管理员(op)权限 \\\\普通玩家管理\\\\ \/kick ——踢出某玩家 \/list ——列出当前在线玩家 \/setidletimeout ——[仅java版]设置踢出待机玩家的等待时间 \\\\服务器保存\\\\ \/save-all ——[仅java版]保存当前的服务器 \/save-off ——[仅java版]关闭服务器自动保存 \/save-on ——[仅java版]开启服务器自动保存 \/save ——[仅基岩版]对服务器的保存进行操作 \\\\服务器运行[仅java版]\\\\ \/stop ——关闭服务器 \\\\白名单管理\\\\ \/whitelist ——管理服务器白名单(注:在基岩版中,该指令时不时被重命名成\/allowlist) 多人游戏指令的绝大多数早就在java正式版发布前就定型了,后续版本几乎没有动过它们。因此对于很早期的多人游戏指令我们就不提了。 大多数多人游戏指令都简单易用且很短小,甚至有些指令连参数都没有。需要注意,这些指令中,除了\/list和基岩版中的\/kick指令,其他指令均无法在命令方块中运行。 在接下来的章节中,我们将学习这些指令的具体用法(这还用学吗?)以及在实际应用中应该注意的问题。 多人游戏指令历史 \\\\java\\\\ ssic 0.0.15a——多人测试中,加入一系列多人游戏指令:\/ban、\/banip、\/broadcast、\/deop、\/kick、\/op和\/unban命令 0.0.16a_01——\/broadcast被改成\/say indev 0.31——移除了所有指令 alpha 1.0.16——加入了多人游戏指令:\/ban、\/ban-ip、\/banlist、\/deop、\/kick、\/op、\/pardon、\/pardon-ip和\/stop 1.0.16_01——加入了\/save-all、\/save-on和\/save-off v1.0.16_02——加入了\/list beta 1.3——加入了\/whitelist 正式版 1.7.2——加入了\/setidletimeout 1.8.1——为list加入了uuid子命令 \\\\携带版和基岩版\\\\ 携带版alpha 0.16.0——加入了多人游戏指令:\/deop、\/op、\/list 基岩版 1.16.0——加入了\/kick和\/whitelist 1.17.0——\/whitelist在“被改成\/allowlist”和“保持原样”间反复横跳,最终还是保持原样。 未来——\/whitelist又被改成\/allowlist 第五十一章 whitelist-白名单 在minecraft服务器中,有一个很重要的系统:白名单系统。 什么是白名单?简单来说,白名单就是服务器随身携带的一个小本本,上面记录了一些玩家。当一个服务器启用白名单系统后,每个玩家想要进入服务器时,服务器就会从兜里掏出小本本,看看该玩家是否被记录在小本本上。如果有记录,那么服务器会允许玩家游玩服务器,反之则会拒之门外。 可以说,有了白名单系统,服务器就能够几乎不受熊的骚扰。对于java服务器来说,白名单再加上正版验证,那安全性简直不要太好。 minecraft服务器的白名单系统简单来说由两部分组成:服务器根目录下的whitelist.json文件和\/whitelist指令。(注:作者没有开过基岩版minecraft服务器,暂不清楚基岩版服务器是否和java版服务器情况一致。如果有开过基岩版服务器的读者可以在这儿留言说明一下。) 这个whitelist.json文件内用json记录了白名单上的玩家数据。这个玩家数据的组成也很简单:由玩家名和uuid组成。 在java版服务器中,开启正版验证的情况下,玩家名和uuid都有用处。因为每个正版玩家都有一个独一无二的uuid和玩家名。什么是uuid?简单来说,uuid就是你在minecraft中的身份证号码,游戏需要通过uuid来识别你。uuid可以通过mojang提供的官方api接口进行查询,因此可以保证不会有玩家冒充某个获得白名单的另一个玩家进入服务器。 至于基岩版服务器。基岩版服务器没有离线账号一说,全部账号都是xbox的游戏账号,因此也有独一无二的uuid。 但如果没有开启正版验证,离线服务器的白名单就没有那么保险了。至于为什么会不保险,我们待会再研究。 白名单的另一部分是\/whitelist指令。该指令的使用方法如下: \/whitelist add <玩家名>——将玩家添加到白名单,并且该玩家不需要在线。 \/whitelist list——列出白名单中的玩家。 \/whitelist off——在此服务器上禁用白名单系统。 \/whitelist on——在此服务器上启用白名单系统。 \/whitelist reload——从服务器文件夹中重新读取white-list.txt(1.7.5及以前)或whitelist.json(1.7.6及以后)文件中的白名单列表。 \/whitelist remove <玩家>——将玩家名从白名单中移除。被移除的玩家不需要在线。 是不是很简单?我们现在来看一个情景: 当天下午,某名玩家通过mc百科的找服玩功能找到了一个开启了正版验证和白名单系统的1.12.2版本java服务器,并通过了该服务器的白名单获取考试和qq群加入审核。现在服务器管理员要将该玩家加入到服务器白名单列表当中,他一共可以采取三种方法来完成这项任务: 1暂时禁用服务器白名单功能(运行\/whitelist off),等待该玩家加入服务器。该玩家加入服务器后,管理员运行“\/whitelist add 该玩家名称”将该玩家加入白名单中,最后再运行\/whitelist on开启白名单功能。 2与该玩家私聊,获取该玩家的玩家名信息。让该玩家先尝试加入一遍服务器,然后服务器管理员打开服务器根目录的usernamecache.json文件(该文件记录着玩家名和对应的uuid),根据用户名找到对应的uuid,接着手动修改whitelist.json文件,最后运行\/whitelist reload重载白名单。 3与该玩家私聊,获取该玩家的玩家名信息。然后直接运行“\/whitelist add 玩家名”即可。 很明显,1方案是个下策,风险性很高。2方案如果不是服主或服主的好朋友,否则很难获取服务器目录的访问和修改权。3方案是最好的方案,也是最简单的方案。 现在你学会了吧? 那么为什么离线服务器的白名单不保险呢? 首先,我们要了解:什么是离线服务器。 离线服务器,并不是指可以断网玩的minecraft服务器,而是指没有开启正版验证的服务器。离线服务器不会验证进入的玩家是否为正版玩家,因此自然也不会专门去获取该玩家的uuid(就算该玩家是正版玩家),而是会随机生成一串uuid。由于uuid是服务端随机生成的,那么肯定就无法通过uuid来验证玩家,因为客户端不知道也不会记录服务端随机生成了什么uuid。所以在离线服务器中,唯一能够验证玩家的便是玩家名。 由于离线账号下的玩家名可以不受限制的重复,因此开启了白名单验证的离线服务器就有可能会出现以下情况(该情况根据真实事件改编): a是一名获取了该服务器白名单的玩家,玩家名叫做scp b是另外一名玩家,但玩家名也是scp b有一天尝试直接进入到a所玩的服务器,然后他成功了,并且一开局就有经验值和一堆物品! 很明显,离线服务器就算开启了白名单,只要他人搞到了能够进入服务器的玩家名字,就可以通过“盗取”他人游戏账号来进入服务器,这也就是为什么mojang在每次离线服务器启动的时候都要加上一句警告信息。 而获取能够进入服务器的玩家名字很简单。只要有人在线,就算是没有白名单的人也能通过服务器信息搞到在线玩家名,进而修改自己的玩家名进入服务器。 那么离线服务器能否解决这个问题呢? 有两个解决办法: 1开启正版验证。但是离线服务器玩的人基本上没有正版,所以对于那些玩家来说打击很大。 2不要使用原版的服务端,采用第三方可以装插件的服务端或在原版服务端的基础上装forge再加上spongeforge(海绵端),并给服务器装上适宜的登录插件,让玩家进入服务器还需输入一次密码进行二次验证。 3采用第三方皮肤站或自建皮肤站,修改官方服务端的验证服务器为自己的验证服务器,然后开启正版验证。此时使用指定皮肤站账号的玩家就被服务器视作正版玩家,也就解决了白名单问题,还顺带解决了皮肤显示问题。 第一个解决办法虽然很保险,但是可能会因此丧失几乎所有的玩家(因为玩离线服务器的玩家大多数没有正版账号)。对于已经运行一段时间,有一定体量的服务器来说,最好采用第二个解决办法,顺带还可以给服务器装更多插件,搞得更加高大上一些。对于没多少玩家的新开服务器,还可以采用第三个解决办法,目前很多mc java服务器也是采用这个办法通过开源的blessing skin server自建mc皮肤站来解决皮肤显示和白名单问题。 那么本章就到此结束了。下一章我们将了解黑名单和\/kick指令的使用。(\/kick还要讲吗?是个人都会用!) 第五十二章 kick和黑名单系统 在上一章我们学习了白名单的使用方法。但在mc java版中不只有白名单,还有黑名单系统。 黑名单系统的组成和白名单类似,也是由两部分组成:黑名单相关指令和服务器目录下的黑名单文件。 虽然组成成分类似,但黑名单和白名单还是有许多不同之处。第一,黑名单目前仅在java版服务器中有;第二,黑名单的记录内容比白名单的内容更加复杂;第三,黑名单的作用和白名单是相反的;第四,黑名单系统是一直在运行的,无法关闭 那么黑名单有什么用呢?黑名单和白名单一样,也是服务器随身携带的一个小本本,这个小本本上面也记录了一些玩家(还有ip地址)。当一个玩家想要进入服务器时,服务器就会拿出这个小本本,看一看该玩家的名字和uuid是否被记录在了本子上,然后再看看该玩家的ip地址是否也被记录。只要玩家名和ip地址中两者有任意一者被记录在了本子上,该玩家就无法进入服务器。 没错,黑名单系统就是一个服务器的“封号”系统。但是说成“封号”并不准确,因为“封号”仅指的是封禁整个账号,而黑名单系统不止会封禁账号,还可以封禁ip地址。 什么是ip地址?ip地址(inte protocol address),即互联网协议地址。用人话来说,ip地址就相当于你和其他人在互联网上的邮编,双方都需要通过ip地址才能互相收发邮件。假设你的ip地址是222.216.131.255,你的朋友的ip地址是23.135.160.255,你想要给他发送一条信息,那么这条信息上面就会标注上你作为发信人的ip地址还有他作为收信人的ip地址,这样他才能收到信息。 封禁ip地址,就相当于拒收从某ip地址发来的信息。 黑名单上到底记录了什么信息呢?一项封禁具体有如下信息: 如果封禁的是玩家名,这里会记录该玩家名对应的uuid:xxxxxxxx-xxxx-xxxx-xxxxxxxxxxxx 被封禁的玩家名(name)或ip地址(ip):xxxxxx 该项封禁的创建时间(created):xxxx-xx-xx xx:xx:xx +xxxx 该项封禁的创建人(source):xxxxxx 该项封禁的到期时间(expires):默认为forever 封禁的原因(reason):默认为banned by an operator. 我们该怎样通过指令使用黑名单? 黑名单相关的指令有许多,具体有: \\\\封禁相关\\\\ \/ban <玩家名或uuid>[封禁原因]——通过玩家名或uuid来封禁一名玩家,玩家无需在线。 \/ban-ip [封禁原因]——直接封禁一个ip地址或封禁一名在线玩家的ip地址 \\\\查看相关\\\\ \/banlist ——查看被封禁的ip列表或玩家列表。ips即ip列表,yers即玩家列表。 \\\\解封相关\\\\ \/pardon <玩家名>——解封一个玩家名(从黑名单上移除指定玩家名) \/pardon-ip ——解封一个ip地址(从黑名单上移除指定ip地址) 虽然比\/whitelist指令要复杂一点,但仍然很简单,对吧? 现在我们来看一个情景(本情景为作者瞎编,如有雷同,纯属巧合): 在某生存+小游戏服务器中,有一名叫做klee的玩家(ip地址为1.145.14.191)乱放tnt,放火烧山,给该服务器中的其他玩家造成许多损失。经管理员们讨论后,服务器给予该玩家永久封禁账号(\/ban klee 由于您严重违反我们服务器相关规定,该帐号已被永久封禁)+ip地址(\/ban-ip 1.145.14.191)大礼包,并补偿服务器内的其他玩家每人3万游戏币,同时对受灾严重地区进行回档操作。 如果这名玩家想要再次进入服务器,那么她将会收到一条错误信息:由于您严重违反我们服务器相关规定,该帐号已被永久封禁。 如果这名玩家还不服气,网上买了个黑号打算再进服务器大干一番,只要她的ip地址还是原来的那个1.145.14.191,那么她就永远无法进入该服务器(除非ip地址被解封或她的ip地址换了)。 对了,如何查看一名玩家的ip地址呢? 打开你服务器的根目录,找到logs文件夹。进入该文件夹,找到需要查看的玩家最后上线那天的服务器日志文件。打开后,使用ctrl+f(windows和linux)或mand?+f(mac)搜索该玩家名称,就能很快地找到该玩家的ip信息。 现在你知道如何使用黑名单了吧?就算你学会了,本章也没有到此结束(\/kick还没讲呢!)。 注意到上面封禁的具体信息中有一行封禁到期时间了没有? 你有没有发现,在黑名单的相关指令中,从来没有出现过能够设置封禁时长的参数,每次封禁都是forever(永久封禁)。这究竟是怎么一回事? 实际上,这里藏着一个天大的bug,一个从java1.9甚至更早到现在都未能解决的bug: 当一项封禁到了到期时间,游戏仍然会继续封禁而不是放弃该项封禁。 虽然该bug在1.9版本才被发现,mojang内部员工也说了该bug在1.13.1被解决(mc-),但实际上仍然没有解决(mc-)。根据目前mojang bug反馈网站上显示的信息,该错误影响了原版mc的1.9~1.12.2、1.14.4~1.17版本。如果这个bug在接下来的1.19甚至是以后的1.20版本中被解决,那么mojang很有可能会给\/ban还有\/ban-ip指令添加一个新的可以设定到期时间的参数! 唉,我们是不是漏了什么东西? \/kick啊! \/kick的作用是踢出一名玩家。和黑名单不同的是,被踢出的玩家可以再次进入到服务器中而不受限制,相当于是一个警告或是一个玩笑。 \/kick的语法如下: \/kick <目标选择器:玩家>[踢出原因] 即使\/kick的使用如此简单,我们仍然需要注意以下几点: 1在基岩版中,\/kick可以在命令方块中执行(需要权限等级仅为1)。但在java版中不行(需要3级权限)。 2在基岩版中,\/kick不能踢出服务器的拥有者。但在java版中,这是可行的。 3在基岩版中,\/kick在命令方块执行成功输出的红石信号强度等同于\/kick本次执行所踢出的玩家数量。 本章就到此结束了。 第五十三章 剩下的一些指令 我们知道,在服务器中使用\/list指令就可以列出服务器上的所有在线玩家。 但你知道吗,\/list的语法可不仅仅只有一个“list”,实际上它还有子命令的! \/list的语法具体如下: java \/list ——列出当前服务器上的玩家 \/list uuids ——列出当前服务器上的玩家及uuid 基岩版 \/list ——同java \/listd [信息:ids|stats|uuids]——这是list的一个隐藏变种! 但是作者并不知道\/listd用起来具体怎样,原因很简单: 对于小游戏服务器来说,禁用\/list指令是个基本操作! ....... \/op和\/deop的使用不用多说。唯一需要注意的是在基岩版中,虽然管理员和服主可以通过暂停界面的玩家列表设定某玩家为管理员,但这只是暂时性的,唯有使用\/op才能永久赋予玩家管理员权限。 这是为什么呢?因为管理员的信息同样由一个文件存储(叫做ops.json)着。使用\/op和\/deop都会更改这个文件,但在暂停界面更改玩家为管理员并不会更改该文件,自然就只是暂时性的。 如果你有兴趣去打开这个文件,你就会发现在这个文件中还可以手动配置每个管理员实际的权限等级和该管理员是否可以挤出在线玩家(bypassesyerlimit)。后者是一个特殊的权限,默认是false即关闭状态。如果打开,那么拥有该权限的管理员在服务器满员时进入服务器,游戏将会随机踢出一位幸运儿(普通玩家)并让该管理员能够顺利进入该服务器。 ...... \/setidletimeout指令可以设置踢出待机玩家需要等待的时间,单位为分钟。如\/setidletimeout 5,就是让服务器自动踢出待机超过5分钟的玩家。 ...... 基岩版的\/save指令和java版的save系列指令有所不同。不同之处在于基岩版的save是备份服务器,而java版的save系列指令只是保存服务器。 save指令的具体格式如下: \/save <操作:hold|query|resume> 需要注意,该指令需要4级操作权限,即一般情况下只能在服务器控制台执行! hold操作可以备份服务器,query可以输出上一次服务器备份的文件信息,resume可以还原服务器到上一次备份的样子。 在java版中,save系列指令的格式如下: \/save-off ——关闭服务器自动保存 \/save-on ——开启服务器自动保存 \/save-all [flush]——现在立马保存服务器。如果还给出了flush参数,那么服务器会放下一些用尽全部力量保存服务器(服务器会在保存过程中暂时冻结)! ...... \/stop的使用很简单,功能也很简单,仅仅是关闭服务器。 但请你注意,minecraft的原版服务器仅仅凭借自身无法完成重启操作。服务器如果需要每次执行\/stop都不是关闭服务器而是重启服务器的话,就需要手动为服务器的启动命令再套一些命令。只不过这些命令已经不是minecraft的命令,我们也不需要在本书中去了解它们(因为如果也写它们的话,本书干脆就可以改名叫做命令行使用手册了)。 第五十四章 初识nbt (此章节已于2022年8月1日再次修改) 你肯定很好奇为什么多人游戏指令讲着讲着就突然讲到nbt了。实际上原本这一章讲的是『解封玩家』,但在本书第一次大修过程中这一章的内容被合并到了第五十二章,因此这一章就空了出来。 还有一个原因是,第一次大修过程中,我也去参考了许多其他制作得比较优良的minecraft命令教程,发现他们大多数讲nbt比较早,这样子以后深入时就好展开讲。而本书在第一次大修前,nbt的内容在第100章才匆忙开始。 因此,为了让各位读者能够更好地掌握nbt的相关知识,我们就先在这里初步认识一下nbt。 ———————————— 在第一次听到nbt这个词时,你脑海里肯定会浮现出三个问题: 『什么是nbt?nbt能干什么?我该如何使用nbt?』 nbt,全称named binary tag,中文翻译为二进制命名标签。它在minecraft中你虽然见不到,但它无处不在:在鸡里面、在计分板里面、在玩家里面、在区块里面...... 所以nbt到底是啥? ......... 『看,那里有一个东西!』 单纯这样描述,你估计想不出来也不了解这个『东西』是什么。但如果我这样描述呢: 这个东西的『种类』是『生物』 『生物种类』是『狗』 『毛发颜色』是『黄色』 『品种』是『哈士奇』 『质量』是『33kg』 『主人』是『旁边的那个人』 『年龄』是『5岁』 当我像上面这样描述时,你对这个东西也越发的变得了解。nbt也是个类似的玩意儿,只不过它不光是给你看的,它还是给游戏看的。 在minecraft中,nbt就像上面我描述那个东西所用的方法一样,它也用于『描述』游戏内部的事物: 『命名空间id』是『minecraft:mand_block』 『限制』是『无条件限制』 『坐标』是『45,12,32』 『自动激活』是『关闭』 『内部指令』是『say hello!』 通过上面的描述,你和游戏应该都清楚了,这是一个脉冲型、没有条件限制、处于坐标(45,12,32)、需要红石、写有指令『say hello!』的命令方块。 仔细观察上面的内容,你应该会发现,我们都是使用类似于下面的格式来进行描述: 『一个描述』是『多少』 像上面这样子的一对『描述』和『值』,在nbt中就叫做『标签』。 一个标签具有标签名称和值,标签名称规定了这个标签具体是干啥用的,值则描述了这个标签具体是怎么干的。标签名称和值使用英文半角冒号分开,标签名在左,值在右。比如: health:20.0f 这个标签的名称是『health』,代表着这个标签用来记录着这个东西的生命值。值是『20.0f』,代表着这个东西当前的生命值为20.0(你先不用管f是啥)。 标签和标签之间使用英文半角逗号区分,比如: health:20.0f,customname:“what?“ 一堆像这样的标签,就组成了一个nbt标签: {health:20.0f,customname:“what?“} 一个nbt标签内有一个或多个标签,外面被花括号所包围。nbt标签其实还可以嵌套作为值成为『复合标签』,下面会具体讲到这个东西。 和json文本一样,标签的值也有许多类型,具体的我们到以后再详细了解,这里就先简单介绍一下。 值的数据类型可以粗略分为五种:数组、数值、文本、复合标签和列表。数组以后再讲,现在我们只需要来认识一下剩下的四种。 数值类型,也就是一串数字。一般这一串数字为整型数,比如: {dimension:10} 但有些标签的值也可以是浮点数,如: {health:7.8f} (f在这边代表值类型为单精度浮点数,一般情况下可以省略这些后缀字母,但如果出了问题还是要加上的) 什么是整型和浮点数?简单来说,整型就是整数数据类型,也就是整数;浮点数是一种看起来很像小数的表示方法。其中,后者具有小数点,既能表示整数也能表示小数。比如: 10 10.0 虽然这两个数大小一样,也都是整数。但在计算机眼中,上者是『整型数』,下者是『浮点数』,并不一样。 文本类型,也就是一串文本。和数值不一样的是,文本需要使用英文半角引号将内容包裹起来。如: {customname:“arcaea“} 在java1.14及以上版本中,引号也可以使用半角单引号: {customname:''arcaea''} 复合标签类型听起来很高大上。但只要你语文好一点,就会发现它并没有多么高大上。 『复合』的意思是:把两种或几种成分结合起来。所以『复合标签』的意思就是:把多个标签结合起来。在这边,这个标签并不是普通的标签,而是由多个标签组合成的nbt标签: {标签名:{标签名:值,标签名:值......}} 也就是说,复合标签本质上,其实就是将一个nbt标签塞到另一个nbt标签里面去: {riding:{id:“xxxx“,health:20.0f},id:“yyy“} 列表类型常常与复合标签类型结合使用。它长这个样子: {标签名:[值,值,值,值......]} 列表类型的本质,就是把多个同类型的值组合在一起。比如: {friends:[“xiaohong“,“xiaoming“,“xiaozhang“]} 这里friends标签的值就是三个文本组成的列表。 刚才说过列表类型常常与复合标签类型结合使用,具体的使用法是这样子的: {标签:[{标签},{标签},{标签}]} 也就是把多个nbt标签(复合标签)组合成一个列表。在以后我们会经常性地遇到这样的用法。 这就是nbt,或者说,是mojang专门研发出来能够给人看的:snbt(stringified nbt),也就是『字符串化的二进制命名标签』。而真正的nbt,其实是树状结构,和上面的snbt有很大差别。只不过你不用担心怎么区分nbt和snbt,因为干嘛要管呢?在大多数语境下,大家是不会特意区分nbt和snbt的,一般都统称为nbt。 现在你能够看懂nbt了吧?你可以尝试一下下面的这串,看看能否看懂。 {elements:[{name:“pyro“,id:1},{name:“hydro“,id:2},{name:“anemo“,id:3},{name:“electro“,id:4},{name:“dendro“,id:5},{name:“cryo“,id:6},{name:“geo“,id:7}]} 本章就到这里了。 (其实,标签的本质,和json的组件差不多,都是一个『键-值对』) 第五十五章 effect-牛顿哭了 如果你现在要自定义一个僵尸小boss,你会怎么做? 使用nbt是最好的方式。但是如果是要在基岩版里面做呢?况且你现在也不会使用nbt,也就看得懂的水平罢了。 在这种情况下,我们就需要使用多个指令来达成目的,比方说可以使用\/receitem(\/item)指令来给僵尸上装备。 但血量和防御力该怎么修改? 其实不难修改,我们只需要使用一个特别的东西:状态效果 状态效果(status effect)在minecraft中非常有用,甚至可以提高生物的血量上限和防御力。我们可以使用指令\/effect来给生物添加、清除状态效果: \/effect 作用:给一或多个实体添加或移除状态效果。 需要权限等级:java-2,基岩-1 需要作弊:是 格式: java1.13更新之前和基岩版: \/effect <目标选择器> clear ——清除目标所拥有的所有状态效果。 \/effect <目标选择器><状态效果id>[<持续时间:秒>][<强度等级>][<是否隐藏粒子和图标:布尔值>]——给予目标指定的状态效果。 java1.13更新后: \/effect clear <目标选择器>[状态效果id]——清除目标所拥有的所有状态效果,或只清除指定的状态效果 \/effect give <目标选择器><状态效果id>[<秒数>][<强度等级>][<是否隐藏粒子和图标:布尔值>]——给予目标指定的状态效果。 格式总体来说还是十分简单的。现在让我们来试试给这只僵尸添加一个状态效果: \/effect @e[type=zombie,c=1] regeneration(java1.13更新前和基岩版) \/effect give @e[type=zombie,limit=1,sort=nearest] regeneration (java1.13更新后) 运行上面的指令,游戏将会给离执行地点最近的僵尸添加30秒的1级生命恢复效果(僵尸:危)。 如果我们想要将这个状态效果移除,可以使用: \/effect @e[type=zombie,c=1] clear (java1.13更新前和基岩版) \/effect clear @e[type=zombie,limit=1,sort=nearest](java1.13更新后) 这两条指令将会清除离执行地点最近的僵尸所拥有的所有状态效果。但如果这个僵尸拥有其他我们不想清除的状态效果怎么办? 在java1.13及之后的版本中,我们可以执行\/effect clear @e[type=zombie,limit=1,sort=nearest] regeneration来清除生命恢复效果而不清除其他状态效果。可是在java1.13前的版本和基岩版中似乎没有清除指定状态效果的方法呀? 还是有的。 想一想,当目标已经有了指定的状态效果,我们再添加一个状态效果上去会发生什么? 再想一想,当两个名称、类型一样的文件相遇的时候,计算机会给你提示什么? 想到了没有?没错,只有两种可能性:覆盖和保留原来的状态效果 而minecraft选择了什么呢?两者均有。当目标具有相同的状态效果时,游戏将会根据以下情况选择是保留还是覆盖: 1新状态效果持续时间比源状态效果要短,且持续时间不等于0,保留原来的状态效果 2新状态效果持续时间比源状态效果要长或相等,覆盖原来的状态效果 3新状态效果持续时间为0,移除原来的状态效果(实际上也是覆盖)。 发现了没有?我们可以通过添加一个持续时间为0的状态效果来移除指定的状态效果: \/effect @e[type=zombie,c=1] regeneration 0 这样子就成功保住了那只僵尸的命。而且,这个方法在java1.13更新后仍然可用。 状态效果的持续时间最大为秒(11.574天),如果指定更大的值将会被视为秒。默认的持续时间是30秒,即半分钟。(注,在基岩版1.16.200版本之前,持续时间最大为,但超过秒的话就没有效果了) 持续时间的单位一般是秒,但有三个状态效果的值例外:瞬间伤害、瞬间治疗和饱和。它们三所使用的单位是游戏刻,默认的持续时间也被改为了1游戏刻。毕竟是“瞬间”嘛,一“瞬间”持续太长时间就不正常了。 现在可以尝试给我们的僵尸boss加血量上限了: \/effect @e[type=zombie,tag=boss] health_boost (java1.13前和基岩版) \/effect give @e[type=zombie,tag=boss] health_boost (java1.13更新后) health_boost是“生命提升”效果,可以提升生命最大值。上面的指令将会为我们的僵尸boss增加4点生命值上限,持续秒。 对于一个boss来说,24点血也太少了。因此我们要提高生命提升的等级。生命提升效果能够增加的最大生命值等于强度等级乘4的积。作为一个小型boss,100点血就足够了,也就是说我们需要给僵尸添加20级的生命提升: \/effect @e[type=zombie,tag=boss] health_boost ,19(java1.13前和基岩版) \/effect give @e[type=zombie,tag=boss] health_boost ,19(java1.13更新后) (注:上面的逗号仅用于区分两个参数之用,实际在游戏中无需输入逗号) 你肯定会疑惑:不是添加20级吗,怎么是19级? 其实这就是添加20级。只不过这个“强度等级”参数有些特别,它的值范围是0~255。输入0相当于1级,输入1相当于2级.......输入255相当于256级。 明白了吧? 现在我们成功为僵尸提高了生命值上限。但是状态效果是有粒子的,到时候玩家过来打这个boss,发现这个boss有冒出粒子,不就露馅了么? 解决办法很简单。看见那个“是否隐藏粒子和图标”参数了没?默认它是false,如果将它改为true,游戏将会隐藏该状态效果的粒子,在java版甚至还会把图标也给隐藏了。 现在你学会\/effect了没?赶紧去游戏中尝试一下吧! (注:在minecraft中,状态效果持续时间超过1638秒的话,效果的持续时间将显示为**:**。在java版中,计时仍然会照常进行。) (你知道吗:在java版中,当玩家拥有超过128级的跳跃效果时,玩家会因为特性而无法跳跃!) effect历史: java 1.5——加入了\/effect 1.6.1——加入了clear参数 1.8——加入了“是否隐藏粒子和图标”参数 1.13——更改了\/effect的语法 1.15.2——较强效果覆盖较弱效果时,较弱效果只是被隐藏了。 携带版和基岩版 \\\\携带版\\\\ 1.0.5——加入了\/effect \\\\基岩版\\\\ 1.16.200——现在持续时间上限和java版一样为秒了。 第五十六章 clone-拷贝方块 在电脑上右键任意一个文件或在手机上选中任意一个文件,你肯定会看见一个操作:拷贝(复制) 不只是文件可以拷贝,文字、图片也可以拷贝。 minecraft也是在电脑和手机上运行的,那么minecraft可以拷贝吗? 当然可以,因为minecraft本身就是由多个文件组成的。 但是minecraft里面的方块呢? 其实也是可以的,但并不是长按或选中,而是使用一个特殊的指令:\/clone。 \/clone(克隆)指令,可以将一定范围的方块选中然后复制并粘贴到它处。 听起来这操作是不是很简单?听上去确实很简单,但实际操作就有些门道了。 \/clone 作用:拷贝(或剪切)选中范围内的所有或部分方块,并覆盖到它处。 需要权限等级:java-2,基岩-1 需要作弊:是 格式: java1.13更新后 \/clone <复制区开始坐标><复制区结束坐标><粘贴区区域基点>[rece|masked][force|move|normal] \/clone <复制区开始坐标><复制区结束坐标><粘贴区区域基点> filtered <需要复制的方块>[force|move|normal] java1.13更新前和基岩版 \/clone <复制区开始坐标><复制区结束坐标><粘贴区区域基点>[rece|masked][force|move|normal] \/clone <复制区开始坐标><复制区结束坐标><粘贴区区域基点> filtered <需要复制的方块><方块数据值|方块状态> 我们要拷贝一个区域内的方块,首先我们要选中一个区域。 clone指令指定区域的方式和\/fill等其他大多数指令差不多,都是指定一个长方体区域的两个对角坐标。 这么说你可能会有些迷糊。这样吧,打个比方: 假设这里有一个长方形的桌子,它有四条腿。如果我们要选中这个桌子,就需要先把这个桌子看作是一个长方体,八个顶点分别是四个桌角和四条腿与地面的垂足(这好像不是个长方体吧?)。然后我们随便选一个顶点的坐标作为第一个对角坐标输入进\/clone里,再选择与这个顶点相对应的顶点的坐标作为第二个对角坐标输入进\/clone里,这样子我们就成功选取了这个桌子。 这下子你应该理解了吧? 选中区域之后就要考虑要复制到哪里,即确定目标区域。目标区域的形状方向大小和源区域是一模一样的,唯一的区别只是位置的不同。因此我们只需要确定目标区域的区域基点坐标即可。 什么是区域基点坐标?这是个专业说法,简单来说就是目标区域的下西北角坐标。关于这东西其实我们在第三十七章就接触过了: “比较时先通过\/fill选择区域的方式确定源区域,再与要比较区域进行比较。只不过这个要比较区域的位置填写就挺蛋疼:你得找到要比较区域的下西北角(专业术语叫做区域基点)。 哪里是下西北角呢? 区域内xyz三个值最小的地方。 这两个区域的大小由第一个定,所以比较的区域就直接给一个角了。 以后的\/clone指令(复制指令)也是这种形式。” ——引自《minecraft指令手册》第三十七章:testforblock、testforblocks-探测下 成功确定并输入目标区域基点坐标后,你就可以运行指令将源区域内的所有方块拷贝过去了。注意,这将会覆盖原本区域内的所有方块!而且minecraft中可没有撤销操作,请确定你所输入的坐标均完全正确! 这是最简单的拷贝方式。\/clone实际上给我们提供了三种复制模式和三种拷贝模式。 三种复制模式是: rece——默认,全选 masked——仅复制非空气方块,这将会保留目标区域中原本会被替换成空气的方块 filtered——仅复制指定方块 三种拷贝模式是: normal——默认,即普通的复制并粘贴 move——剪切,即复制粘贴后把源区域全部替换为空气 force——强制拷贝,和normal模式的唯一区别是即使目标区域和源区域一模一样还是拷贝。 比如: \/clone 1 1 1 2 2 2 10 10 10 masked move 运行这条指令,游戏将会剪切源区域(1,1,1)-(2,2,2)到目标区域,且仅复制源区域内的非空气方块。 上面的3+3模式中,唯一需要稍微讲一下的就是filtered模式。 filtered模式和其他模式最大的不同在于,它多了一到两个参数:方块(基岩版和java1.13更新前版本还多了“数据值或方块状态”参数) 使用filtered,可以指定需要复制什么方块。比如: \/clone 1 1 1 2 2 2 ~,~,~,filtered air normal(java1.13更新后) \/clone 10 5 10 30 30 30,~,~,~,filtered normal air -1 (java1.13更新前和基岩版) (上面的逗号仅供区分参数之用,实际不需要逗号,请忽略) 运行上面的指令,游戏只会复制空气方块到目标区域。如果目标区域都是非空气方块,你将会惊喜地发现目标区域变成了源区域的形状! 这就是filtered的用处之一,可以将目标区域改造成源区域的形状而不影响其原本方块构成。或许你还能想到更多奇妙的用处。 \/clone指令的内容就这么多。注意:和\/fill一样,\/clone一次性最多只能拷贝个方块! 第五十七章 enchant-简单的附魔 你或许会在某些地方发现一些玩家能够拥有不合常理等级的附魔,比如一把拥有级锋利的剑。他们究竟是怎么做到的呢?如果让他们来回答这个问题,他们极有可能会直接搬出下面这条指令: \/give @p xxx x x {ench:[{id:xx,lvl:xx},{id:xx,lvl:xx}]} 许多他们的粉丝看了这串指令之后就兴冲冲地跑去网易我的世界(手机端),然后执行这串指令,接着那些粉丝们就会惊奇地发现:没用啊! 当然会没用。在基岩版的指令中nbt几乎没有用武之地,自然也就无法成功运行这串指令。 对于那些被蒙在鼓里的粉丝们来说,这件事可能影响不大。但对于那些基岩版网易租贷服的服主来说,不能使用nbt来自定义附魔确实是很麻烦。 为什么麻烦呢?没了nbt,这些服主在正常情况下就只有两种选择来搞自定义附魔。一种是手动使用铁砧附魔,另一种就是使用一个特殊的指令: \/enchant 作用:为目标玩家(主手)手持的物品添加魔咒 需要权限等级:java-2,基岩-1 需要作弊:是[仅基岩版] 格式: \/enchant <目标选择器><魔咒id>[等级:int] 举个例子: \/enchant @e[type=skeleton] me 这条指令将会给所有骷髅手上的弓附魔上火矢。 使用\/enchant指令附魔具有许多局限性: 1目标必须手持着需要附魔的物品,如果没有手持指定物品将会附魔失败。 2在java版中,如果目标的手持物品已经带有要附魔的魔咒,附魔将会失败。在基岩版中,如果目标的手持物品已经带有要附魔的魔咒,且等级和给予魔咒的等级一样,魔咒等级将会升一级(但仍然不会超过正常情况的上限)。比如给一个附魔了耐久i的钻石剑再附魔一遍耐久i,在java版会失败,在基岩版则会让耐久i变成耐久ii。 3赋予的魔咒等级不能超过正常值,即你并不能使用\/enchant来附魔出一把具有级锋利的剑,那将会导致附魔失败。 4需要附魔的物品必须要能接受赋予的魔咒,否则附魔将会失败。如你并不能使用\/enchant将时运附魔到铁剑上。 5需要附魔的物品已经拥有的魔咒中不能有会与新魔咒出现冲突的魔咒。如你并不能使用\/enchant把时运和精准采集都附魔到同一个镐子上面。 看看,这些条条框框的,比直接使用铁砧附魔还要麻烦。只不过\/enchant还是有两点好处的,一是使用\/enchant附魔不会增加物品的累积惩罚,二是\/enchant作为一条指令可以自动化执行。 (注:累计惩罚是物品的一个属性,作用于铁砧中每次操作需要的经验等级。累计惩罚越大,需要的经验等级就越多。) 和\/effect一样,\/enchant的魔咒id参数在java1.13之前的版本和基岩版中,数字id和英文id均可使用,在java1.13更新后的版本只能使用英文id。 至于具体的id列表,大家去minecraft wiki上查看吧。注:java1.13之前的版本,魔咒、状态效果的数字id与现今基岩版是完全不一样的,因此只能在wiki的历史记录中查找! 现在你会用这使用起来极其麻烦的指令来附魔了吗?快去游戏中试一试吧! 第五十八章 使用nbt来自定义附魔 在前一章,我们了解到在java版也可以使用nbt来自定义附魔。那么具体该如何自定义呢? 先让我们来看看上一章那些拥有不合常理等级附魔的玩家,他们给出的指令如下: \/give @p xxx x x {ench:[{id:xx,lvl:xx},{id:xx,lvl:xx}]} 你应该还记得java1.13更新前的\/give格式吧: \/give <目标选择器><物品id:字符串>[<物品数量:整数>][<物品数据值:整数>][nbt标签] 对比一下,你会发现这些玩家给出的指令格式是完全正确的,因此我们只需要关注nbt部分。 在第五十四章中,我们已经初步了解了nbt的样子。让我们来试一试你能不能看懂这个nbt: {ench:[{id:xx,lvl:xx},{id:xx,lvl:xx}]} 很明显,这个nbt标签只有一个ench标签,这个标签的值类型是列表,而且是由多个复合标签组成的列表。而那些复合标签内的两个标签id和lvl的值类型是个整型数。 格式看懂了,但我们还不知道怎么用,如何用。其实用起来很简单,如果你会一点英文的话那就更简单了。 ench这个单词,实则是英文单词enchantment \/?n''t??ntm?nt\/(魔咒)的缩写,再联系它的值是个列表,也就不难理解ench标签的作用:储存物品的附魔信息。 在minecraft中,一个魔咒一定拥有有两个信息:魔咒id和魔咒等级。对应到上面的nbt中,每个魔咒就是列表内的复合标签,魔咒id就是复合标签内的id标签,魔咒等级就是复合标签内的lvl标签。 比如{ench:[{id:34,lvl:10},{id:16,lvl:8}]},在java版就代表耐久x和锋利5iii两个魔咒(注:java版和基岩版的魔咒id并不一样,这里是java版的魔咒id)。也就是说,当你运行\/give @s diamond 1 0 {ench:[{id:34,lvl:10},{id:16,lvl:8}]}时,你会获得一个附魔了耐久x和锋利5iii的钻石。 标签lvl的值的上限是,这就是为什么级的附魔这么出名。 现在你会用了吧?但请注意,以上的所有内容都是基于java1.13更新前的版本和基岩版,在java1.13更新后,情况就不一样了。 在java1.13更新后的版本中,自定义附魔的nbt变成了: {enchantments:[{id:“xx“,lvl:xx},{id:“xx“,lvl:xx}]} 不难发现,附魔用的nbt标签有两个大修改: 1标签ench的名称变成了全称enchantment的复数enchantments 2标签id的值类型变成了字符串,填的是魔咒的英文id 除了这两个显而易见的大修改外,还有一个细微的小修改: lvl的值类型从短整形(short)变成了整形(int)。 这是什么意思呢?简单来说,就是lvl的值上限从提高到了! 没错,在java1.13更新后,你可以附魔超过级的魔咒!可惜这么令人震惊的事情却未能改变目前大多数玩家的潜意识,很多玩家仍然认为级就是最厉害的。 java1.13更新过后,如果你要获得一把级锋利的剑,你就需要执行: \/give @s diamond_sword{enchantments:[{id:“sharpness“,lvl:}]} 注意,这条指令仅适用于java1.13~1.17,这是为什么呢? 因为在java1.17.1,mojang做了一个更改:lvl的值重新被改回short短整型,且限定制值范围到0~255之间。 也就是说,在目前的java最新版本,自定义附魔等级的上限最高只能是255级! 这太糟糕了!但255级好像也完全够用就是了。 本章到此为止。 第五十九章 更深入地了解坐标 在此之前,我们已经学习了绝对坐标和相对坐标。 你有没有发现,很多事情往往都与“三”这个数字挂钩,因此minecraft中是否还有第三种坐标呢? 在解答问题之前,我们先来看看2022年minecraft新春会。 在minecraft新春会中,很多红石音乐节目往往会出现由粒子效果画出的圆形。现在让我们来思考一下,圆形是怎么做出来的? 我们要画一个圆,就得用到圆规。使用圆规画圆时,首先得确定圆心,然后确定半径,最后在保证圆心不偏移的情况下在纸上旋转圆规一圈,就成功画出了一个圆。 在minecraft中画圆也同理。首先需要确定圆心,也就是在圆心处固定好一个盔甲架,然后确定半径.......等等,半径怎么确定? 这里,我们就要用到minecraft中的第三种坐标:局部坐标(也称本地坐标) 局部坐标使用“^”符号,写法跟相对坐标一样,都是数字跟在符号后面。比如“^2 ^3 ^-3”。 虽然写法和相对坐标一样,但它相较于相对坐标有许多不同之处。 局部坐标虽然单位长度仍然是一个方块的棱长,但它的三个坐标轴在大多数情况下并不能与绝对坐标的三个轴重合,因此它不能与绝对坐标还有相对坐标一起使用。 而且,局部坐标的原点也很特殊——它的原点是执行者的头! 某玩家:“头作为原点有啥好判定的?不就是上下前后左右嘛。” 哎,这位玩家竟然说对了,局部坐标说白了真的就是“上下前后左右空间直角坐标系”!在局部坐标中,xyz轴分别代表: x——左(+)右(-)方向 y——上(+)下(-)方向 z——前(+)后(-)方向 比如上面的“^2 ^3 ^-3”,就代表了以执行者的头为原点,向左偏移2格,再向上偏移3格,最后向后方偏移3格的点(注意,是主观上的左右前后上下)。 因为局部坐标脱离了minecraft的绝对坐标还有相对坐标,所以局部坐标非常有用且在很多方面都不可替代。就比如上面我们要确认半径,就得用且只能用局部坐标。 有了局部坐标后,我们在minecraft中画圆也就很简单了。接下来我们来实践尝试一下(注:以下指令的版本均是java1.13.2): 1使用“\/summon minecraft:armor_stand 88 10 125 {nogravity:1,customname:“\\“a\\““,invulnerable:1,customnamevisible:1,invisible:1}”在(88,10,125)处生成一个叫做a的隐形的不会掉落的不会受到伤害的盔甲架。 2放置一个重复的命令方块,在里面填上“\/execute as @e[name=a] at @s run particle dust 1 0 0 2 ^,^,^10 0 0 0 0 5”(那边的逗号是用于区分参数的,请忽略)。这条指令的意思是:将执行者和执行基准点设为a和a所处的位置,并执行particle指令,在盔甲架的正前方10格处生成数量为5且速度为0的红色烟雾。 3再放置一个重复的命令方块,填上“\/execute at @e[name=a] run tp @e[name=a]~~~~2 ~”,它的作用是让盔甲架水平顺时针旋转2度。 4运行上面的两个重复命令方块,你会惊奇地发现红色烟雾开始转动了! mnecraft新春会的那些粒子效果固然会比这复杂许多,但原理一样,差别仅在于minecraft新春会的指令规模更大,且更复杂(因为需要严格控制路径、速度和时间,与音乐搭配好)。 对了,在minecraft中快速生成圆环、圆盘甚至是圆柱也是同样的道理。 现在你会局部坐标了吗? 本章到此为止。 (注:在java1.13之前的版本,指令中无法使用局部坐标。) 历史 java 1.13——加入了局部坐标 基岩版 ?——加入了局部坐标 第六十章 基岩版的json文本(破200收藏纪念) json文本在java版很常用。在基岩版虽然能用的地方少了很多,但仍然很有用处。 基岩版的json文本主要用于指令、书与笔的文本和告示牌的文本上。由于基岩版指令的限制,我们只能在\/tellraw和\/titleraw两个指令中用到json文本。虽然能用的地方极其少,我们仍然得学习学习,就因为\/tellraw这条指令极其有用。 基岩版的json文本的基础格式如下: {“rawtext“:[]} 在基岩版中,每串json文本的最外层必然是rawtext组件。rawtext的值是json对象列表,也就是由多个json对象组成的列表。你可以把json对象看作是nbt中的复合标签(两者其实没多大差别),方便理解。 基岩版的json文本组件相比java版要少许多。不算rawtext的话,基岩版一共只有五个组件: \\\\内容组件\\\\ text(值:文本) selector(值:文本) trante(值:文本) score(值:json对象,相当于nbt的复合标签) \\rante配套组件\\\\ with(值:由多个文本组成的列表) 最基础的组件还是text,用法和java版的一模一样: {“rawtext“:[{“text“:“hello!“}]} 这解析后会变成:hello! 你有没有注意到,基岩版甚至连文本颜色格式组件都被阉割了,也就是说我们无法使用color组件来修改文字颜色。既然我们无法使用color之类的组件,那么我们该如何修改文本的颜色和格式? 你是不是忘记了一个东西:§ 由于基岩版可以自由使用§来修改文本的颜色和格式,因此mojang就把color之类的文本颜色格式组件给切了。 在基岩版的json文本中使用§,需要注意两点: 1§必须要放在内容组件的值中,不能放在组件名等其他地方。虽然放在其他地方在命令方块中也会生效,但json文本就无法被游戏正确识别并输出了。 2使用§后记得要及时用§r来重置文字样式,不然会把§右边的所有文本都修改了样式。比如: {“rawtext“:[{“text“:“§ehello!“},{“text“:“minecraft“}]} 这将会输出:hello!minecraft(都是黄色) 如果是{“rawtext“:[{“text“:“§ehello!§r“},{“text“:“minecraft“}]},则只会把“hello!”一段变成黄色。 selector组件可以输出实体名称,其值必须填的是目标选择器。比如: {“rawtext“:[{“selector“:“@p“}]} 这将会输出距离执行地点最近玩家的名称。假设距离执行地点最近的玩家叫做『phigros』,那么这将会输出:phigros selector的使用还是很简单的。但请注意,你不能把selector当做text一样使用。原因很简单:其值必须是个目标选择器。 如果你把selector当做text一样用,比如这样子填写: {“rawtext“:[{“selector“:“hellominecraft“}]} 你会惊奇地发现执行指令后,没有任何的文本输出,也没有任何的报错信息。 这是为什么呢?因为selector的值必须是个目标选择器,你这样填就相当于要输出玩家hellominecraft的名称,而游戏中又没有叫做hellominecraft的玩家,自然就不会输出。但如果真的有一个叫做hellominecraft的玩家且在线,就会正常输出『hellominecraft』。 trante组件是这五个组件中最难的一个,因为它有些涉及到minecraft的模组、资源包开发。为何这么说?因为trante组件可以让一段文字以目标玩家的语言输出。 在学习trante的用法之前,我们要了解一个东西:本地化键(也称『翻译识别符』) 每一种语言都有自己对应的语言文件,比如美式英语对应的就是en_usng,中文简体对应的就是zhng。游戏中同一个地方的文本会翻译成不同的语言。这时候问题来了:我们该如何在不同的语言文件中正确找到用于这个地方的文本呢? 这时候本地化键就出场了。 把一个地方的文本在不同语言中的翻译都绑定到一串不变的id上,根据id找到对应的翻译文本,不就解决这个问题了吗? 举个例子,在下面两个不同的语言文件中分别有这么一行: en_usng: server.help.getgold=you can get gold by selling items and ying games.for example, you may get 500 coins if you win a game of bed war.# zhng: server.help.getgold=您可以通过售卖物品、玩小游戏来获得金币。比如当你赢得一局起床战争时,您可能会获得500枚金币。# 我们只需要在需要用到这一串文本的地方放上『server.help.getgold』,游戏就会自动根据不同的语言将这一串本地化键替换成对应语言的文本。 json文本内的trante组件就是干这行的。在trante的值内写上本地化键,游戏就会根据不同的语言将对应的内容呈现出来。比如: {“rawtext“:[{“trante“:“server.help.getgold“}]} 如果你使用的是中文简体,最终这将会输出:『您可以通过售卖物品、玩小游戏来获得金币。比如当您赢得一局起床战争时,你可能会获得500枚金币。』 如果你使用的是美式英语,这反而会输出:『you can get gold by selling items and ying games.for example, you may get 500 coins if you win a game of bed war.』 现在你明白了吗? (注:上面这个server.help.getgold本地化键是编的,但接下来的几个本地化键都是真实存在于游戏中的。) trante的使用肯定没有这么简单,这只是最基础的用法而已。有时候,本地化键对应的文本内会有一些特殊的部分。比如『death.attack.onfire』,如果你只是这么用它: {“rawtext“:[{“trante“:“death.attack.onfire“}]} 最终它会输出: %1$s 被烧死了 这是怎么回事?因为我们没有指定死亡的东西是什么。如果我们要指定,就得用到trante的配套组件:with with的值是由多个文本组成的列表。至于为什么是个列表,是因为有些时候会有多个特殊的部分,这时候就需要使用列表来分别指定每个部分是什么。 我们待会再研究具有多个特殊部分的情况。先来试试使用with指定死亡的东西是『张三』: {“rawtext“:[{“trante“:“death.attack.onfire“,“with“:[“张三“]}]} 这将会输出:张三被烧死了 现在我们再来看看有多个特殊部分的情况: {“rawtext“:[{“trante“:“death.attack.arrow.item“}]} 这将会输出:%1$s 被%2$s 用%3$s 射杀 这句话虽然很短,但有三个特殊的部分。如何正确指定这三个特殊部分呢?按照从左到右的顺序指定: {“rawtext“:[{“trante“:“death.attack.arrow.item“,“with“:[“枯藤“,“老树“,“昏鸦“]}]} 这会输出:枯藤被老树用昏鸦射杀 一般情况下,特殊部分会按照从左到右的顺序一一对应列表内的元素。在上面的例子中,%1$s最靠左,“枯藤”也在列表的最左边,因此%1$s就被“枯藤”替换了。剩下的%2$s和%3$s同理。 这就是trante组件一般的用法。除了这个用法外,trante还能被当做text组件一样用,且比text组件多出了一个没啥用的功能:自定义特殊部分 特殊部分有两种自定义的格式: %%s %%#(#为列表内元素从左到右排列的序号) 先来说说%%s。%%s的用法和上面的%1$s、%2$s之类的一模一样,都是从左到右一一对应。比如: {“rawtext“:[{“trante“:“你好%%s!这里有一些关于%%s的说明。“,“with“:[“新手“,“空岛战争“]}]} 这会输出:你好新手!这里有一些关于空岛战争的说明。 %%#的功能和%%s比较不一样。%%#的#实际上是列表内各个元素从左到右的排列数字。比如%%1在上面的列表中就代表着『新手』。也就是说,如果这样子填写: {“rawtext“:[{“trante“:“你好%%1!这里有一些关于%%1的说明。“,“with“:[“新手“,“空岛战争“]}]} 最终会输出:你好新手!这里有一些关于新手的说明。 上面的例子中,%%s和%%#都是独立使用。如果两者一起使用会发生什么呢? 来看看下面这个例子: {“rawtext“:[{“trante“:“欢迎来到%%s,%%1!您今日的%%s还未领取!“,“with“:[“easecation“,“每日签到奖励“,“一个普通的路人“]}]} 猜一猜,最终这会输出什么? 你是不是以为,最终这会输出:欢迎来到easecation,easecation!您今日的每日签到奖励还未领取! 如果你这样想,就错了。实际上输出的是:欢迎来到easecation,一个普通的路人!您今日的每日签到奖励还未领取! 这是怎么一回事?当%%s和%%#一起使用的时候,游戏会优先把%%s替换掉。按照从左到右的原则,第一个%%s被替换成了『easecation』,第二个%%s被替换成了『每日签到奖励』。然后游戏才会替换%%#。这时候神奇的地方来了,由于%%s使用过的列表元素%%#就不能再使用,因此%%#的顺序得从第三个元素开始算起,最终导致%%1被替换成了『一个普通的路人』。 这就是trante和其配套with组件的全部内容,你学会了吗? 最后的score组件简单且有用,它可以显示记分板上的分数。 score的值是json对象,你可以把它当做是复合标签。对象内有三个子组件: name——选择正在被记分板追踪的目标,显示ta的分数,值为文本。必须填写目标选择器或玩家名(假的也可以)。 objective——计分项名称。值为文本。 value[可选]——值为文本。如果指定了该项,不管真实的分数是多少,都会显示为该项的值。 (注:作者实验时发现value组件没用,可能在目前的基岩版最新版中已经删去了该标签。作者实验的版本是基岩版1.18.2) 举个例子。假设玩家liben在计分项primogems上的分数为2431,我们可以这样输出他的分数: {“rawtext“:[{“score“:{“name“:“liben“,“objective“:“primogems“}}]} 这将会输出:2431 需要注意,当name选定的目标为多个时,游戏将会按照目标选择器排列的顺序输出每个目标的分数。 现在你会使用基岩版的json文本了吗?注意,一个json对象内不能有多个内容组件。当一个对象内有多个内容组件时,权重高的组件的内容将会覆盖权重低的组件。四个内容组件的权重如下: score set <需要追踪的结果类型><被记分板追踪的目标:目标选择器><计分项>——跟踪并获取某个方块运行指令的指定类型的结果,根据结果修改记分板上的分数 \/stats block <坐标> clear <需要取消追踪的结果类型>——取消跟踪某个方块运行指令的指定类型结果 \/stats entity <实体:目标选择器> set <需要追踪的结果类型><被记分板追踪的目标:目标选择器><计分项>——跟踪并获取指定实体运行指令的指定结果,根据结果修改记分板上的分数 \/stats entity <实体:目标选择器> clear <需要取消追踪的结果类型>——取消跟踪指定实体运行指令的指定结果 那么\/stats指令到底该如何使用呢? 指令的输出结果有五种类型: 1指令执行成功的次数(sesscount) 2指令的查询结果(queryresult) 3受到该指令影响的物品数量(affecteditems) 4受到该指令影响的实体数量(affectedentities) 5受到该指令影响的方块数量(affectedblocks) 我们使用\/stats指令时,必须要指定我们到底想要让\/stats指令获取什么类型的执行结果,因为每一种执行结果的值都可能不一样。 比如使用clear指令检测玩家背包内有多少个指定物品时,如果我们获取的是sesscount结果类型,那么只会是1或0;而如果我们获取的是affecteditems,获取到的就是物品的数量。 使用\/stats时,不仅要指定需要获取什么,还要指定两个重要的东西: 1从哪儿获取? 2输出到哪儿? \/stats指令可以跟踪指定的方块和实体来获取执行在它们身上的指令的结果。看到“跟踪”两字没有?没错,\/stats指令并不是立马就获取到执行指令的结果,而是先跟踪指定的目标,比如一个命令方块,只要这个命令方块执行了指令,它就会将指令的结果输出到指定的计分项当中。 \/stats指令会将得到的值输出到指定的计分项并修改该计分项中指定目标的分数。比如\/stats获取到的结果是13,它就会修改分数到13(除非指定的计分项是只读计分项)。 这就是\/stats的使用方法,看起来还是蛮简单的。现在就让我们实践一下,熟悉一下具体的操作流程。 假设这是一个命令方块,它位于坐标12,24,81处——>? 我们要获取整个服务器现在一共有多少名玩家,首先就需要准备一个计分项以及一个正在被该计分项追踪的目标。请注意,必须是在该计分项上有分数的目标,否则\/stats会无法修改分数(因为\/stats指令只能修改分数而不能添加追踪目标)! 假设你已经准备好一个叫做information的计分项和一个正在被该计分项追踪的虚假玩家yers。现在,运行下面的指令: \/stats block 12 24 81 set sesscount yers information 此时游戏会返回信息:将sesscount项统计信息储存在了yers的information上。这样子写可能会误导一些玩家,实际上这时候才开始追踪,并没有开始获取结果并修改记分板上的分数。 为了方便观察,你可以把information计分项显示在侧边栏或其他地方,然后在?命令方块处输入: testfor @a 最后拉下拉杆。假设此时在线玩家为3,你就会发现yers的分数变成3了! 如果你拉下拉杆后服务器又进入一名玩家,此时你再次运行命令方块,你就会发现yers的分数又变为4了! 使用起来是不是很简单?别看用的时候很简单,清理的时候可别搞错了。 使用\/stats指令追踪一个方块或实体,如果我们没有及时停止追踪,游戏就会一直追踪下去!因此,请你最好在指令执行完成后再加一句: \/stats block 12 24 81 clear sesscount 这句指令的意思是:停止追踪?命令方块的sesscount类结果信息 清除时请注意一点,结果类型一定要一样!因为每一个追踪项都是精细到结果类型的,结果类型填错了就变成清理其他追踪项,这点一定要注意!如果你忘记了结果类型,只能把五个类型全部清一遍(mojang没有提供查询追踪项的方式)。 这就是\/stats指令的用法。使用\/stats指令,你可以跟踪获取到方块执行指令的结果、玩家执行指令的结果和作用在跟踪目标上的\/execute子命令运行的结果,并根据这些结果修改记分板上的分数。 对了,使用\/stats时请注意一点,跟踪的目标有没有被其他正处于循环当中的execute指令影响到,如果有的话,获取到的结果就会被污染!!! 现在你会用\/stats了吗?我们下一章见。 stats历史 java 1.8——加入了\/stats指令 1.13——移除了\/stats指令,改用更先进的\/execute存储子命令。关于\/execute在java1.13更新后的使用方式,我们下一卷会讲到。 第六十二章 命令方块矿车 minecraft中的矿车有许许多多的种类。截至目前的1.18.2版本,minecraft一共有如下几种矿车: tnt矿车——会爆炸 动力矿车——像火车一样可以消耗燃料前进 普通矿车——可以运输生物和船(?) 运输矿车——放东西 漏斗矿车——传输物品 刷怪笼矿车——生成生物 命令方块矿车——执行指令 每种矿车都有自己的特点以及独特的用法。比如你可以通过在一个狭窄的空间内堆叠超级多的tnt矿车来制作一个可以秒杀几乎任何生物的爆炸装置。 那么对于命令方块矿车来说,有什么奇妙的用法呢? 观前提示:在了解命令方块矿车之前,请先把矿车的英文和我的世界的英文区分开,因为: 矿车————minecart 我的世界——minecraft 记住,千万不要把矿车和我的世界混在一起了,矿车的英文比我的世界少了一个字母“f”!(基岩版旧版本的翻译就犯了这个错误,用机翻然后把命令方块矿车翻译成“带有命令块的《我的世界》”) 首先,让我们来了解一下命令方块矿车的基本数据。 命令方块矿车(minecart with mand block)的实体和物品id均为mand_block_minecart。它和普通的矿车一样,也是一个实体,唯一的区别就在于命令方块矿车在普通矿车的基础上多了一个迷你的命令方块。 如果命令方块矿车被处于生存模式下的玩家打掉,将会仅仅掉落矿车(不然还会掉落命令方块啊?)。 (注:在java1.11版本之前,命令方块矿车的id是minecartmandblock) 看起来命令方块矿车的本质就是一个会移动的命令方块。但实际上,两者在很多方面都有较大的差异。 第一个差异:种类 和普通的命令方块不一样的是,命令方块矿车的种类是固定死的。在java版中,命令方块矿车的种类被固定成了脉冲型,在基岩版则是循环型。至于为什么要这么搞,待会你就知道了。 (这里其实有个bug,编号mcpe-,就是在基岩版中物品形态的命令方块矿车竟然是脉冲型的,放出来就变循环型了。真离谱。) 第二个差异:激活方式和执行频率 普通的命令方块可以通过红石信号激活,但命令方块矿车作为一个实体该如何感受到红石信号呢?想想tnt矿车是怎么被激活的你就知道了。 命令方块矿车和tnt矿车一样,当它处于激活铁轨上时,就会被激活并执行指令。 你看到这估计没有任何疑问。但别忘了,命令方块矿车虽然不能选择种类,但本质上也是有种类的是不是。既然命令方块在java版是脉冲型,在基岩版是循环型,那么两者是不是不一样呢? 我们现在不打开minecraft,就凭脑子猜一猜,然后你大概率会得出如下结论: 在java版中,命令方块矿车由于是脉冲型,所以当它处于被红石信号激活的激活铁轨上时,只会执行一次。如果需要再次执行,需要先停止激活激活铁轨,然后再次激活激活铁轨才行。 而在基岩版,命令方块矿车是循环型,所以当它处于被红石信号激活的激活铁轨上时,它会一直执行直到没有红石信号。 好,看来你之前学的东西都没有白费,所以让我们打开minecraft验证一下吧! 我们先打开minecraft java(只要有命令方块矿车的版本均可),然后放置一个激活铁轨并在旁边放上拉杆,随后将一个命令方块矿车置于铁轨之上。 为了方便观察,我们这边还需要创建一个计分项,如: \/scoreboard objectives add test dummy 然后在命令方块矿车中输入: \/scoreboard yers add test test 1 最后激活铁轨,令人大跌眼镜的一幕发生了,聊天框中开始出现如下的执行信息: [@:将玩家test的test分数设置为1] [@:将玩家test的test分数设置为2] [@:将玩家test的test分数设置为3] [@:将玩家test的test分数设置为4] ....... 你这不是脉冲型吗,怎么一直在重复执行? 然后我们可以再打开minecraft基岩版,也按照上面的实验流程进行,你也会发现现象是一致的。 这究竟是怎么一回事?其实命令方块矿车是个很神奇的东西,不管它的外观是脉冲型还是循环型,它在两个minecraft版本中的特性都是一致的: 当其位于被激活的激活铁轨上方时,命令方块矿车会以4游戏刻为周期循环执行指令,即正常情况下每秒会执行5次。 也就是说,命令方块矿车本质上是循环型,只不过是频率比较慢的循环型而已。 (所以mojang,你在java版搞这个外观是干啥呢?误导人是吧。) 这就是命令方块矿车与普通命令方块的第二个差异。 第三个差异:红石比较器 和命令方块一样,命令方块矿车也可以通过红石比较器检测命令的运行情况。但毕竟矿车是个实体,这导致如果要检测命令方块矿车的话,就得用红石比较器检测处于命令方块矿车下面的铁轨才能检测到命令方块矿车。 需要注意,这里的铁轨不是普通的铁轨,也不是激活铁轨,而是探测铁轨,就是中心有一个正方形的那个! 上面这三个差异就是命令方块矿车和命令方块最主要的差异了。那么命令方块矿车有什么用呢? 命令方块矿车和普通的命令方块相比,最重要的一个特点就是可以移动,特别是可以按照预定的线路移动,所以命令方块矿车很适合运用在空间需要不断变化的场景内,比如: 我们需要自动铺路、挖掘机,并对美观没有太大要求,直直的即可 这种情况下命令方块矿车就很有用了。但实际上,命令方块矿车最常见的用处并不是在这里,而是在ooc(only one mand),即“仅有一条指令”。 啥意思呢? (考虑到这东西会涉及到下落的方块的使用、实体的骑乘属性还有nbt,所以这里我们就先简单介绍一下,不过多深入。) 想一想,在minecraft中,你是不是可以骑在马上? 你应该知道在minecraft中,每个实体都有一个nbt,那么当你骑在马上的时候,你和马是两个独立的个体还是被看作是一个个体呢? 从外观上来看,是两个个体。但如果你此时查看一下马的nbt,你就会发现在nbt层面,你们俩合二为一了! 没错,在nbt层面,你的实体nbt被嵌套进了马的nbt里面! 好,那么我们现在想一想,从理论上来说,你可以骑在羊上吗?或者说甚至是一些其他的实体,如你可以骑在玩家上吗? 我们先不要过早下结论,让我们来看看2022年4月1日mojang发布了个什么惊人更新: one block at a time update(一次只拿一块更新) 在这次更新中,你可以和其他玩家叠高高,也就是骑在玩家身上,而且最高还可以叠5层! 这说明了什么?这就说明了,玩家也是可以骑在玩家身上的。 但为什么玩家在这次更新就可以被骑了呢?是不是mojang为了实现这个功能把马的骑乘模块移到了玩家身上? 答案并不是这样的,而是玩家本身就有骑乘模块,或者说minecraft中的所有实体都有骑乘模块,只不过mojang仅仅让少数实体可以应用这些模块而已。 所以从理论上来说,你是可以骑在羊身上的,甚至你可以说,你可以骑在任何实体身上! 那么这跟指令以及命令方块矿车有什么关系呢? 现在让我们再来看看另一个东西:下落的方块。 下落的方块,名字听起来是个方块,但实际上它是个实体。 你可能认为你从来没有见到过下落的方块,但实际上,你很容易就可以遇见它。 在minecraft中,如果一个受到重力影响的方块(如沙子)要落下,那么游戏就会将其转换为“下落的方块”这个实体,并将方块的相关数据存储于实体nbt中,等到实体落到地面之后游戏再将其转换回去。 既然下落的方块是个实体,那么我们就可以通过summon指令将其生成。并且,由于方块的相关数据都存储于实体nbt中,所以我们可以通过指令来召唤特定的“下落的方块”。比如,你可以召唤出一个“下落的钻石块”,这个实体版的钻石块照样会在落到地面时变回方块版的钻石块。 好,你现在听懂了吧,但这又跟命令方块矿车有什么关系呢? 想一想,如果我们使用summon命令,召唤一个“下落的红石块”,这个“下落的红石块”上面骑着“下落的激活铁轨”,而这个“下落的激活铁轨”上面又骑着一个命令方块矿车,最后,这个命令方块矿车里写了一串指令:say hello minecraft。 听着有点晕是吧?正常。简单点说,就是你召唤了一个叠高高,这个叠高高一共有三层,最上面一层是写有“say hello minecraft”指令的命令方块矿车,中间一层是正处于下落状态的“激活铁轨”,最下面一层是正处于下落状态的“下落的红石块” 能够明白了吧?想一想,当这个“叠高高”到达地面时,会发生什么事情? 红石块会先落到地面并回到方块形态,然后激活铁轨就会因为红石块变回方块而也变回方块形态,随后被红石块激活。命令方块矿车接着会落到激活铁轨上面,并开始重复执行指令。最终你的聊天栏就会不断出现“hello minecraft”的消息。 是不是很神奇?仅用一条指令,就执行了........say hello minecraft?这本来就可以一条指令做到啊,搞这么复杂有毛病啊?! 没有毛病。别忘了,既然命令方块矿车可以骑在下落的方块上,那不也能骑在命令方块矿车上吗?而且由于铁轨方块的特性,同一个铁轨上可以有许多个矿车卡在一起。所以从理论上,你可以通过“叠高高”的形式召唤一大堆的命令方块矿车,这些命令方块矿车可以分别执行不同的指令,但你召唤它们仅需要一条十分十分十分长的指令即可。 这就是ooc(only one mand),即“仅有一条指令”在游戏中真正的表现形式。 (其实还有一种表现形式,就是召唤叠高高的“下落的命令方块”,照样也可以实现类似的功能,就是比较占地) 现在你知道命令方块矿车有何作用了吧? (你知道吗,在基岩版1.17尚未更新时,命令方块矿车有一个恶性bug,编号mcpe-。 这个bug的内容很简单:游戏规则mandblocksenabled用于控制命令方块是否启动,但这个规则管不到命令方块矿车,这就导致就算关闭了mandblocksenabled这个规则,命令方块矿车也可以运行命令。 在当时,许多基岩版的服务器就因为这个bug遭到了破坏,mojang也是很快地在有人反馈后就在1.17更新中修复了这个bug。现在已经没有这个bug了。) 第六十三章 游戏声音 (观前提示:此章有部分内容涉及到初中物理的知识) 在之前,我们已经大致了解了方块、实体、状态效果、粒子效果这四个在minecraft中相当常见的四种东西,还学习了一部分基础的游戏运作机制。接下来,我们就要来看看不管是在minecraft还是在其他游戏,都具有十分重要地位的东西——游戏声音。 在minecraft中,游戏声音主要包括以下三类: 普通音效——由玩家、生物、物品、实体和方块发出的声音,如玩家破坏方块、鹦鹉学舌、武器损坏、射出的箭落地、熔炉工作。 环境音效——这并不是指背景音乐。一般来说,这是指在特定情况下才会播放的声音,所以才带有『环境』二字。比如你在挖矿时突然听到的怪声,那其实就是一个环境音效。关于这东西我们会在第一百五十章讲调试界面的mood值时再次提到。 音乐——一般来说,指的是游戏背景音乐。(c418的音乐针不戳) 当然,如果要分类得更细一些,那就得按照minecraft游戏中的分类,也就是你在设置界面中看到的那十类:主音量(master)、音乐(music)、唱片机\/音符盒(record)、天气(weather)、方块(block)、敌对生物(hostile)、友好生物(neutral)、玩家(yer)、环境(ambient)、声音\/语音(voice)。 你在minecraft中听到的每个声音,肯定都包括有以下信息: 1声音名称(在sounds.json[je]或sound_definitions.json[be]中所规定的声音名称。下面会详细讲一下这东西怎么弄到。) 2声音类别(按照minecraft内的分类来分) 3声音目标(这个声音给谁听,也就是能够被哪些玩家听到,是一个目标选择器或玩家名、uuid) 4声源位置(声音产生的地点,是一个坐标) 5音量(音量越大,声音可闻范围越大,是一个小数。下面会详细讲解这东西) 6音调(自己把物理书或乐理书拿出来翻一下看看,是一个小数。下面也会详细讲解这东西) 7最小音量(指定在声音可闻范围外的最小音量,是一个小数。下面也会详细讲解这东西) 其中,我们需要详细讲解的东西有四个:声音名称、音量、音调和最小音量。 ——1.声音名称 在上面有提到,声音名称是在一个叫做sounds.json[java版]或sound_definitions.json[基岩版]的文件中规定的。那么这个文件在哪呢? 想要找到这个文件可是个技术活,如果你嫌麻烦可以去看minecraft wiki,我们会在章末讨论如何找到这个东西。在此之前,你只需要在minecraft wiki上查找声音名称即可。 ——2.音量 声音的音量在这里并不只是影响声音的响度。音量是一个≥0.0的小数(浮点数)。音量对声音的影响有两种情况: 1当0.0≤音量<1.0时 音量越小,声音响度会相对减轻,直到完全没有(0.0)。声音的球状可闻范围也会相应减小一些。 2当音量≥1.0时 声音响度会不变,但其可闻范围和音量大小的关系符合下面的函数关系式: 可闻范围(单位:米)=音量x16 比如音量为1.2时,该声音的可闻范围就是1.2x16=19.2米。 另外,我们还要了解一下声音的可闻范围: 声音的可闻范围是一个球体,其中心就是声源位置。越远离中心,声音的大小就会越小,直至无声。 ——3.音调 音调是什么?物理学对音调的定义是:声音频率的高低叫做音调。在minecraft中虽然有些不同,但也跟声音频率有关。 这个东西要深究起来非常复杂,在这里我们简简单单了解一下。 音调的值是个小数(浮点数),在java版中是一个在0.0~2.0(含)范围内的数,其对声音的影响可以分为两种情况: 1当0.0≤音调<0.5 等同于音调值为0.5的情况 2当0.5≤音调≤2.0 音调越低,声音的频率越低,持续时间越长。 音调越高,声音的频率越高,持续时间越短。 音调等于1.0时,声音的频率和持续时间均为正常水平。 (如果你并不能很好理解上面的描述,那我就举个例子:当你在观看视频的时候,如果你加快播放速度,声音的波就会挤在一起,频率变高,使得视频的声音变得尖锐,而如果你放慢速度,声音的波反而会离得更开,频率变低,使得视频的声音变得低沉。当然,现在诸如b站之类的视频平台大多都对倍数播放添加了优化,使得视频变快或变慢不会影响到视频音调的改变,但你还是可以在诸如pr之类的视频剪辑软件中体验到这种效果) (也就是说,从某种意义上来讲,这个音调的作用其实就是让你像看b站视频一样倍数播放声音,只不过没有优化声音频率的效果而已) 在基岩版中,其值并没有任何限制,但必须要在0.0至256.0(含)之间才能有效果。如果大于256.0,最终的情况相当于音调等于1.0的情况,也就是默认情况。如果小于等于0.0,声音将会不可听见。 值在0.0至256.0之间的效果类似于java版在0.5和2.0之间的效果。 ——4.最小音量 前面我们讲音量时提到了可闻范围,默认情况下声音会在可闻范围之外不可听见。为什么要说一个『默认情况』呢?因为默认情况下声音的最小音量的值是0.0。 上面我们了解过,声音的最小音量是指在声音可闻范围外的最小音量,是个小数(浮点数),默认为0.0,也就是不可听见。在基岩版中此值无限制,可正也可负,在java版此值必须在0.0~1.0(含)之间。 …………… 现在我们已经讲了很多,但了解这些东西有什么用呢?难不成我们可以用指令来控制游戏声音? 答案当然是能啦,不然我写这个章节干嘛? mojang为minecraft添加了两条声音相关的指令:\/ysound和\/stopsound \/ysound 作用:播放一段声音 需要权限等级:java-2,基岩-1 需要作弊:是 格式: java版 \/ysound <声音名称><类别><目标:目标选择器>[声源位置:坐标][音量][音调][最小音量] 基岩版 \/ysound <声音名称>[目标:目标选择器][声源位置:坐标][音量][音调][最小音量] 看起来这\/ysound指令参数很多啊,但如果你仔细一瞧,就会发现这些参数我们上面都讲过了。 其中我们唯一要讲的就是『类别』这个参数。类别有哪些呢?让我们来看看前文是怎么说的:『声音类别(按照minecraft内的分类来分)』 那么minecraft内部对声音的分类有哪些? 其实已经写在了开头:『主音量(master)、音乐(music)、唱片机\/音符盒(record)、天气(weather)、方块(block)、敌对生物(hostile)、友好生物(neutral)、玩家(yer)、环境(ambient)、声音\/语音(voice)』 懂了吧,那么我们现在来看一个例子。 假设你要播放出洞穴的环境音效,该怎么办? 第一步,你需要打开minecraft中文wiki,搜索sounds.json,找到这个叫做sounds.json的条目(或者找到环境音效这个条目也可以)。第二步,往下拉找到数据值,根据你对应的游戏版本点击展开,往下滑并看着『声音事件』这一列,找到洞穴环境音效的声音事件名称(也就是声音名称),复制。第三步,在minecraft里运行如下指令: \/ysound ambient.cave ambient @a ~~~ 1.0 1.0 0.0 ——java \/ysound ambient.cave @a ~~~ 1.0 1.0 0.0 ——基岩 然后你就听到了和你在洞穴里听到的一模一样的声音。但是如果你多次播放就会发现一个问题:怎么每次播放都是不同的声音啊? 其实一个声音名称对应的不只是一个声音文件,像是ambient.cave这个名称对应的就有19个声音文件。游戏在播放ambient.cave这个声音时其实会在这19个声音中点兵点将点到谁就播放谁,播放的具体是哪个其实完全是随机的。当然,虽然说是随机,但游戏也有规定权重在其中,哪个声音文件权重大就有更高几率抽到那个声音。 \/ysound是播放声音,相对应就还有一个\/stopsound用来停止播放声音。 \/stopsound 作用:停止声音播放。 需要权限等级:java-2,基岩-1 需要作弊:是(java版不需要) 格式: java \/stopsound <玩家:目标选择器>[声音类别][声音名称] 基岩 \/stopsound <玩家:目标选择器>[声音名称] 玩家这个参数在这边用于指定要停止谁的声音,也就是让谁听不到声音。 如果仅仅指定了玩家,将会停止该玩家所听到的所有(游戏中的)声音,也就是让这个玩家的耳朵突然安静下来。你也可以额外指定声音类别和声音名称两个参数,来指定具体要停止什么声音。 举个例子: \/stopsound @a block entity.tnt.primed ——java \/stopsound @a random.fuse ——基岩 这两条指令都将会停止tnt嘶嘶作响的声音。 看起来上面的指令没有丝毫的问题,但仅仅是看起来而已。 如果我们不知道entity.tnt.primed属于哪个声音类别怎么办?毕竟wiki上可没有标出这个的类别。 答案很简单,我们只需要: \/stopsound @a * entity.tnt.primed 不去管就行了!管它干什么?!多管闲事啊?浪费精力又浪费时间。 当你不知道也懒得知道你要停止的声音的类别是什么的时候,可以直接选择填写星号来全选全部声音类别。可惜的是,这个版本在低版本行不通(1.12.2就没有这东西,还得老老实实找类别)。 现在我们已经基本上了解得差不多了,如果你认为可以了就前往下一章或去干其他事情吧,接下来我们将会讨论:如何找到那该死的sounds.json。 对于java版,我们首先需要来到minecraft的根目录,也就是找到.minecraft文件夹。对于非官方启动器来说,一般它和启动器位于同一个目录下;对于官方启动器来说,不同系统的情况不一样: windows:系统盘\\用户(user)\\你的用户名\\appdata(这是个隐藏文件夹)\\roaming\\.minecraft\\ mac os:系统盘\/用户(user)\/你的用户名\/资源库(library)\/application support\/minecraft\/ linux:系统盘\/你的用户名\/.minecraft\/ 注:在mac os中,你默认是看不到资源库(library)这个文件夹的。这时候你就要确保此时访达正选择你的用户文件夹,然后点击左上方的前往→前往文件夹,然后在跳出的窗口中输入『资源库』或『library』三个字,就可以临时显示出这个文件夹了。 然后,我们需要来到如下的位置: .minecraft\/assets\/indexes\/或minecraft\/assets\/indexes\/ 在这里,你会发现一堆名称是.json的文件。这是什么东西呢? 你不用管他,也不需要管它是什么东西,用记事本或文本编辑打开你需要的版本即可。打开后,使用ctrl+f或mand?+f开启查找模式,然后输入sounds.json,你就会找到一个唯一的结果:“minecraft\/sounds.json“:{“hash“:“xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx“,“size“: xxxxxx} 是不是感觉这似乎在哪里见过?其实这就是json,和之前讲过的json文本的格式是一模一样的。 接下来,你需要将hash的值复制下来,然后来到如下文件夹: .minecraft\/assets\/objects\/或minecraft\/assets\/objects\/ 你会看到一大堆不明意义的文件夹,不用担心,直接使用搜素功能,搜索你刚刚复制的内容,稍等片刻,你就会找到一个文件名和你复制内容一模一样的文件。虽然它没有后缀名,但其实它就是我们要找的sounds.json文件。右击使用记事本或文本编辑打开它,如果你找对的话,你就会看到开头写着: { “ambient.cave“:{ “sounds“:[ “ambient\/cave\/cave1“, “ambient\/cave\/cave2“, ……. 如果你的访达或文件管理器迟迟找不到文件,那也别担心,你只需要看看你复制内容的开头两个字符,然后找到相对应的文件夹。比如开头是『97』就找叫做97的文件夹,找到后,你再仔细翻一翻就可以找到了。 sounds.json的json结构大致是这样的: {“声音名称”:{“声音文件”:[声音文件列表],”声音字幕本地化键名”:”一个本地化键名”},……} 懂了吧?当然,sounds.json只是在1.7.2版本后才被弄到如此离谱的地方。在1.7.2版本,sounds.json很好找,它就在这里: .minecraft\/ assets\/或.minecraft \/virtual\/legacy\/ 而且文件名就叫sounds.json 如果你同时安装了1.7.2和更新的版本,那么两类sounds.json文件都将会同时存在。 (那对于比1.7.2更老的版本呢?) (根本不用找,因为没有sounds.json。这东西是在1.7.2才被添加进来的) 另外,对于java版的资源包来说,其也有sounds.json文件,就在资源包的\/assets\/<命名空间>\/下,且就叫sounds.json。 sounds.json找到了,那么基岩版的sound_definitions.json在哪呢? 很好找……….个屁!但至少没有那么多弯弯绕绕的。 对于windows10版本来说,你需要找到: 系统盘:\\program files\\windowsapps\\microsoft.minecraftuwp_应用版本号_x64__8wekyb3d8bbwe\\data\\resource_packs 打开resource_packs,你会发现里面有一大堆叫做vani_<游戏版本>的文件夹。不用管这些,你只需要找到没有后缀的『vani』文件夹,点进去,再找到sounds文件夹,再向下滑,就是sound_definitions.json文件了。整个目录下来是这样的: c:\\program files\\windowsapps\\microsoft.minecraftuwp_应用版本号_x64__8wekyb3d8bbwe\\data\\resource_packs\\vani\\sounds\\sound_definitions.json 对于android版本来说,最简单的办法是安装一个mt管理器,然后将你手机上的minecraft打包成安装程序apk文件,然后再使用mt管理器通过zip视图打开,再打开split_install_pack.apk,来到assets\/resource_packs\/vani\/sounds,就可以找到sound_definitions.json了。 对于ios和其他版本来说…….抱歉,我不清楚。 现在我们两个文件都找到了,本章也就到此结束。 历史 java 1.6.1——加入了\/ysound 1.7.2——加入了sounds.json 1.9——\/ysound支持tab自动补全了,并开始要求使用source参数。更改了许多声音名称。 1.9.3——加入了\/stopsound 携带版 1.0.4——加入了sound_definitons.json 1.0.5——加入了\/stopsound和\/ysound 第六十四章 tp和teleport-深入地了解传送指令 我们在第九章中学习了tp指令的用法,让我们来复习一下: 『\/tp 作用:将一个实体传送到另一个实体或者是坐标。 需要权限等级:java-2,基岩-1 需要作弊:是 格式: \/tp [传送目标:目标选择器]<目的地实体:目标选择器> 这可以将选定的目标传送到另一个实体的位置,比如把张三传送到李四的位置。注意,目的地实体不能为多个,即你并不能将张三传送到李四和王五的位置(就算张三不止一个也不能这样干)。如果将传送目标省略,那么将会传送执行者自己(一般是你自己)。 \/tp [传送目标:目标选择器]<一个地点:坐标>[<水平旋转角度><垂直旋转角度>] 这可以将选定的目标传送到一个指定的地点。』 看起来丝毫没有问题,游戏中也能用对吧? 但其实,tp并没有这么简单。正如我在第九章开头所说的:『这条指令深究起来很复杂』。现在,深究的时候到了。 在minecraft中,传送指令并不只有tp,还有一个teleport。这个teleport虽然是tp的全称,但这两个指令在minecraft java 1.13版本更新之前有很大区别,直到1.13版本更新中两者才被统一,tp才正式作为指令teleport的简写指令。 接下来,我们将会分两步走:先探究指令tp与teleport在minecraft1.13版本前的差异,然后再研究1.13版本赋予了这两者什么样的新内容。 ——第一步:tp与teleport在minecraft java1.13版本更新前的差异 相比tp指令,\/teleport指令虽然比tp更早加入,但很快就被tp取代,直到minecraft1.10版本才被重新加入。在当时,看起来这个\/teleport的单词更长,更厉害,但实际上相比tp,这个玩意儿可以说是十分鸡肋。 怎么个鸡肋法呢?来看看\/teleport的介绍,你就知道了。 \/teleport(je1.13更新前) 作用:同\/tp,传送实体至一个指定的地点 需要权限等级:je-2 be-1 需要作弊:是 格式: \/teleport <传送目标:目标选择器><目的地:坐标>[<水平旋转角度><垂直旋转角度>] 你对比对比一下楼上的tp指令,就会发现teleport的功能比tp还要少,仅仅只能将目标传送到一个指定的位置。而且这样的格式tp也有一模一样的,根本就不需要teleport啊! 所以这就是tp与teleport的区别,我们下一章再见。 …… …… …… …… …… …… 你以为mojang真的这么傻吗,添加一个完全可以被替代的指令,而且用起来还比那个指令还要麻烦? 其实,teleport看起来简单,但实际上这只是它的冰山一角而已。 我们先不管teleport。来回顾回顾我们当时学坐标的时候,我在章末写了如下内容: 『相对坐标的原点实际是因指令而异的,在大部分情况下原点即是指令执行的位置,但也有特殊的情况,如java1.13版本之前的\/tp指令。』 唉,这个\/tp怎么就特殊了呢? 我在第九章有举一个例子:\/tp @p ~~~ 90 0 当时,我举这个例子是用来说明旋转角度的使用,并给出了如下解释: 『这将会使最近的玩家朝向正西而不改变其位置。』 重点来了!如果tp的相对坐标是采用指令执行的位置作为原点,那么当这条指令在命令方块里运行的时候,应该是会把这名玩家传送到命令方块的位置并让其朝向正西方向,而不是让他留在原地。而事实是他留在了原地,并没有被传过来。 这说明了什么? 这说明了,tp指令的相对坐标采用的是传送目标的位置作为原点,而非指令执行的位置。 那如果我们把tp换成teleport呢? 运行\/teleport @p ~~~ 90 0,然后你就会惊喜的发现,那名玩家不仅仅再次朝向了正西,还跑到了命令方块那里! 这就是teleport与tp最大的区别。当然,在现在的基岩版和最新的java版中,tp也已经变成以指令执行的位置作为相对坐标的原点了,所以如果你在基岩版或最新的java版运行上述两个指令,将会得到一模一样的结果。 但别忘了,除了相对坐标,还有相对旋转角度呢!让我们来看看我在第九章举的另一个例子: 『\/tp @p ~~~~-30 ~1 假设这@p选中的还是上面那位被迫朝向正西的玩家,那么这条指令将会使他朝向南偏西60°,头微微朝下1°。』 不难发现,tp的相对旋转角度也是基于传送目标的相对角度。那么teleport呢? 假设这里有一只猪,我们对它使用如下指令: \/teleport @e[c=1,type=pig]~~~~-90 ~90 然后开启第三人称,运行这条指令。仔细观察这头猪,你就会发现这头猪在传送到你身上那一刻,身子和你成了90°角。 这说明了什么?这说明了,teleport的相对旋转角度也是基于命令执行者的旋转角度,而不是基于传送目标的。 (但是这头猪的头并没有朝下看啊) (因为猪的ai强迫它向前看,所以它在正常情况下无法朝下,只要你实验过就会发现这个问题) 现在我们来总结一下: 在je1.13版本更新前,\/tp和\/teleport的区别不仅仅是在格式上,还有相对坐标和相对旋转角度的区别。tp的相对坐标和相对旋转角度基于传送目标,而teleport是基于命令执行者的。 所以je1.13版本前的tp和teleport算是彻底搞清楚了,接下来我们将看看新版的tp和teleport究竟做了怎样的更新吧! ——第二步:新版本的tp与teleport 正如在前面说的,je1.13将tp和teleport指令做了统一,tp成为了teleport的别称。也就是说,在新版本,两者是完全一样的,而且相对坐标和相对旋转角度都统一成以指令执行地点和执行者的旋转角度为基准。 所以格式呢?如下: \/tp和\/teleport 作用:你知我知天下知。 需要权限等级:java-2基岩-1 需要作弊:是 格式(teleport可替换为tp): ——java版1.13及之后 \/teleport [传送目标]<一个实体>——将选中的目标或执行者传送至指定实体的位置 \/teleport <一个位置>——将执行者传送至指定位置 \/teleport <传送目标><一个位置>[<水平旋转角度><垂直旋转角度>]——将选中的目标或执行者传送至指定位置 \/teleport <传送目标><一个位置> facing <朝向坐标>——将选中的目标传送至指定位置,并让其朝向另一个位置 \/teleport <传送目标><一个位置> facing entity <朝向实体>[朝向部位]——将选中的目标传送至指定的位置,并让其朝向一个实体 ——基岩版 \/teleport [传送目标]<一个实体>[安全检查:布尔值]——将选中的目标或执行者传送至指定实体的位置 \/teleport [传送目标]<一个位置>[安全检查:布尔值]——将选中的目标或执行者传送至指定位置 \/teleport [传送目标]<一个位置>[<水平旋转角度><垂直旋转角度>][安全检查:布尔值]——将选中的目标或执行者自己传送至指定位置 \/teleport [传送目标]<一个位置> facing <朝向坐标>[安全检查:布尔值]——将选中的目标或执行者自己传送至指定位置,并让其朝向另一个位置 \/teleport [传送目标]<一个位置> facing <朝向实体>[安全检查:布尔值]——将选中的目标或执行者自己传送至指定位置,并让其朝向一个实体 看起来格式非常的多,但其实仔细看的话,相比我们之前学的,mojang无非就添加了三个新功能: 1可以指定朝向的坐标或实体 2可以检查传送目的地的安全性(仅基岩版) 3未指定传送目标,也就是传送执行者自己到一个指定位置的时候,也可以更改旋转角度了(仅基岩版)。 其中,我们要讲解的是前两个。 首先,可以指定朝向的坐标或实体是一个非常重磅的功能,因为它十分有用。在本章的番外中,作者就利用了这个功能制造出了『我在这儿』的宇宙广播功能,只不过这个番外马上就要撤掉了,因为有些新东西要讲。 那么这个功能怎么用呢? 不很简单吗?你看了上面的作用简介估计就懂了一半了,所以我们直接上例子: \/tp @p ~~~ facing ~~1 ~ 这条指令相当于\/tp @p ~~~ 0 -90,最终都会让这名玩家朝天上看,但前者是让玩家直接朝着命令执行地点的上方看,后者则是通过修改这名玩家的垂直旋转角度使其向天上看。 还有一个例子: \/tp @p ~~~ facing entity @e[limit=1,type=viger,sort=nearest]——java \/tp @p ~~~ facing @e[c=1,type=viger]——基岩 这条指令将会把最近的玩家传送至指令执行地点,并使其朝向最近的一名村民。 有趣的是,如果你运行\/tp @s ~~~ facing entity @s,即让你朝向你自己,你将会发现不管你传送前的姿势多么奇怪,传送后你总会水平地朝向正东方向(java)或正南方向(基岩版)。 相信你在看完上面两个例子已经会用facing了吧?基岩版中facing就这么个用法,但在java版中还有一个参数:朝向部位 这个参数你可以填写两个东西:eyes或feet 填eyes,代表你要让传送目标完成传送后面朝对方的眼睛,填feet,则代表面朝对方的脚。默认是朝向对方的眼睛,但你也可以改成看脚。 比如: \/tp @s ~~~ facing entity @r feet 这将会让你随机看向某一个玩家的脚。 很简单吧。等等,不对,有些问题。 如果你确实按照上面的指令来,你就会发现你看到的并不是这位玩家的脚,而是和这位玩家的眼睛平视。 为什么? 如果你尝试将feet改成eyes,你就会发现你的视角竟然看向了这位玩家上方。 唉mojang,你这是不是bug啊?设置为看脚,却看向眼睛;设置为看眼睛,却看向眼睛的上方。 其实这不是bug,而是跟这个tp指令有关。 tp指令,说是『将一个实体传送到另一个实体或者是坐标』。其实更加确切地说,是这样的: 将一个实体的脚部传送到另一个实体的脚部或者是一个指定的位置。 也就是说,tp指令在传送实体时,其实是传送这个实体的脚部。 为什么呢?想想,如果tp是传送你的眼睛,那么你传送过去,身体是不是要埋半截在土里啊?如果tp是将你的脚传送到另外一个实体的眼睛,那么你传过去,你的脚是不是要踩在那个实体头上啊? 所以mojang为了使传送能够符合我们人的直觉,就将默认传送的部位设定为了脚。 因此,当tp的facing计算朝向的时候,也是以传送目标的脚的坐标(也就是你脚的坐标)来计算的。而如果你从你的脚看向对方的脚,是不是就是平视?看向对方的眼睛,是不是就要仰头? 并且,不管是基于眼睛还是基于脚来计算朝向,最终都会体现在玩家以及其他实体的头部(因为对于有人形的实体来说,头部的朝向决定了该实体的水平旋转角度和垂直旋转角度,而不是身体决定),所以就造成了上面奇怪的结果。 懂了吧? 第二个『安全检查』就更加简单了,你只需要选择是否开启即可(true或false) 如果开启安全检查,会发生什么呢? 其实这个安全检查很鸡肋,仅仅会检查传送目的地是否有足够的空间以防止你窒息,如果不会才会传送,但这并不能防止你掉进岩浆或摔死。 这些内容就是现在版本的tp和teleport,简单吧? 那我们下一章再见。 ……… ……… ……… ……… 虽说全部内容已经完了,但是还是有一些疑问以及一些注意事项。 上面说到过,在新版中,相对坐标和相对旋转角度都统一成以指令执行地点和执行者的旋转角度为基准。但是这句话并不严谨,因为在基岩版中,相对旋转角度还是以传送目标的原先旋转角度为基准来计算的。 有点乱啊,理一理: je1.13前,tp的相对坐标和相对旋转角度都以传送目标的为基准,而teleport则反之。 je1.13之后,tp和teleport均采用指令执行地点和执行者为基准。 基岩版中,tp和teleport的相对坐标均采用以指令执行地点为原点,但相对旋转角度却是以传送目标为基准。 理一理之后确实清楚了许多,但由此就有了一个新的问题: 当相对旋转角度以执行者的为基准时,如果执行者不是个实体而是方块该怎么办,比如命令方块? 其实部分方块也有朝向,但最多也就六个方向,东西南北上下而已。难不成当方块运行tp时,相对旋转角度会采用方块的朝向作为基准朝向? 想得太多了,方块虽然有朝向,但方块又不是实体。当诸如命令方块之类的方块运行指令时,甚至是函数这种连实体都没有的东西运行指令时,指令执行地点和朝向都是默认值,即(0,0,0)和水平朝向正南。 那么本章也就到此正式,真的结束了。 本书第一次大修新增章 1 矿词与标签 这一章原本是第六十四章的番外,但由于内容感觉十分水就去掉了。 所以这里就变成了多出来一章,写什么呢? 这一章我们不妨来填一下一些之前挖的坑。 我们在第二十六章讲到family参数时,提到了这么一句话: 『记分板、nbt和标签可以很好的解决这个问题。但在了解这三个东西之前,我们暂且没有除多弄命令方块以外的更好的办法。』 计分板我们已经了解过了,nbt我们会在100章开始进入正式学习阶段。 那么这个『标签』是什么东西?计分板标签吗? 我们知道,minecraft java版可以装上各种第三方的模组加载器(mod loader),其中最出名的就是minecraft forge。在minecraft1.13版本更新之前,minecraft forge内有一个重要的系统:矿物词典(oredictionary)。 『矿物词典』又是什么鬼?这跟『标签』有什么关系? minecraft forge官方文档中对『矿物词典』的定义如下: 『矿物词典(oredictionary)主要是为了mod间兼容而存在。 已注册到矿物词典的物品将能够代替其它拥有相同矿物词典名的物品。这样就可以使用以上任一物品合成相同的结果。 虽然名字是“矿物(ore)”词典,但是它也可以使用在非矿物的物品上。只要一个物品与另一个物品(比如染料)相似,就都可以注册进矿物词典,并通过矿物词典调用。』 举个例子,在工业时代2(industrial craft 2)模组中添加了铜锭,沉浸工程(immersive engineering)模组中也添加了铜锭,这两个铜锭由于是不同模组所添加的,所以是不同的物品,这就导致一个问题: 假如我死活搞不到工业时代2的铜锭,只能搞到沉浸工程的铜锭,既然都是铜锭,为什么就不能通用啊!!!我还想造ic2的机器呢!!! 于是,矿物词典就来了。沉浸工程的开发者只需要给自家的铜锭添加上一个铜锭的矿物词典(ingotcopper),工业时代2的开发者也只需要给自家的铜锭添加上一样的矿物词典(ingotcopper),然后你就会惊喜地发现,两边的铜锭可以通用了! 当然,实际情况肯定比这更加复杂,只不过我们又不开发模组,干嘛要去管这些更深层次的东西。我们只需要知道: 不同模组类似的物品可以注册到同一个矿物词典中,来使得不同模组的类似物品能够通用。 那么标签又是什么呢? mc百科(mcmod)中对标签的解释如下: 『数据包中的标签(tag)允许玩家使用json文件将物品、方块、流体、实体类型和函数分组,标签在原版 1.13 及以上版本中替代了矿物词典的功能。』 需要注意,这里的原版指的是minecraft java版,基岩版并没有什么矿物词典和这种类型的标签。 看起来很高端的样子啊?但其实这标签仅仅是一个官方逼死第三方的更高端的『矿物词典』。 和矿物词典一样,不同的物品也可以注册到同一个标签中,来使得不同模组的类似物品能够通用。 但在之前,矿物词典最多也仅仅能让物品在工作台中、熔炉中等特定功能性方块中才能通用,官方的标签却更上一层楼,使得类似物品几乎能在任何地方通用! 比如你可以给你自己开发的箭添加上arrows标签,你这个物品就可以被原版的弓和弩射出去;你可以给你自己的食物添加上fox_food标签,这个食物就可以被喂食给狐狸...... 但官方的格局可不止仅仅限制在物品中,让我们把格局打开一点,你就会发现官方让minecraft中的其他东西也能够用上标签来使得其他东西也能够通用。这些『其他东西』一共有十四类,加上物品就十五类了,包括:方块、实体、流体、游戏事件、物品、猫、生物群系、超平坦模式生成器配置、结构、世界预设、画种类、旗帜图案、乐器、兴趣点和函数。 标签在这些其他东西上的运作方式也一样:具有同一个标签的东西,就可以具有同样的功能或性质。 比如拥有frog_food标签的实体,就会被青蛙当成食物来吃;拥va标签的流体,就会具有岩浆的功能;拥有tick标签的函数,会在每游戏刻开始时运行;拥有vige标签的结构,会像村庄一样生成...... 讲了那么多,那这跟指令有什么关系呢? 回到最开始的那句话:『记分板、nbt和标签可以很好的解决这个问题。但在了解这三个东西之前,我们暂且没有除多弄命令方块以外的更好的办法。』 这个问题是什么?就是你怎样才能在目标选择器中一次性选取多个类型的实体。 在基岩版我们可以通过family参数来选择,但在java版呢? mojang在minecraft java1.14中开始为实体添加标签,这就代表着我们在minecraft java1.14及以上版本可以通过标签来对实体进行选择。 怎么选择呢?在目标选择器的type参数中,使用『#+命名空间+标签名称』即可。 比如要选中所有骷髅类型的实体,你只需要: @e[type=#minecraft:skeletons] 这样子就可以选择包括骷髅、凋零骷髅等骷髅类的实体。 而且由于一个实体可以具有多个标签,所以你可以使用多个type参数指定多个标签来筛选。 比如@e[type=#minecraft:skeletons,type=#minecraft:freeze_immune_entity_types],这就可以选择同时具有freeze_immune_entity_types和skeletons标签的实体,即流浪者。 你还可以在#前面加上!来实现『不选择具有指定标签实体』的功能。比如@e[type=#minecraft:skeletons,type=!#minecraft:freeze_immune_entity_types],这就将会排除流浪者,只会选择普通骷髅和凋零骷髅。 只不过和family参数一样,目前mojang给原版实体添加的标签还太少了。但别担心,因为你不仅仅可以使用实体的标签,你还可以使用函数、方块和物品的标签。 比如在指令clear中,你就可以这样子: \/clear @a #minecraft:buttons 这将会清除所有玩家背包中的按钮,不管是什么按钮都行。 也比如在指令execute中,你就可以这样子: \/execute at @a if block ~~-1 ~#minecraft:snow run kill @s 这将会使得所有脚下踩着雪的玩家死亡,不管这个雪是顶层雪还是雪块还是什么其他类型的雪。 (这个execute指令的语法是第八卷,也就是下一卷的内容,我们很快就会学习其具体的用法了) 只不过mojang太懒了,导致在原版中,即使是方块和物品,标签也是太少,发挥不了很大的作用。 那怎么办?装forge啊! forge为原版提供了许多有用的标签,虽然这些主要用途是像矿物词典那样帮助模组互通,但我们指令也是可以用的。 比如使用forge提供的矿物锭标签,就可以实现检测一个玩家背包内所有类型锭的数量: \/execute as @a store result score @s ingot_count run clear @s #forge:ingots 0 这条指令将会将所有玩家背包内任何类型锭的总数量以分数的形式存储在玩家自己的ingot_count计分板中。 所以这就是本章的全部内容了,have you learned it? 第六十五章 worldborder-mc是一款吃鸡游戏 (本章节已于2022年7月12日重修) (本章作者在重修时主要使用的是minecraft java1.13.2进行实验) 我们在第二十八章中讲区块时曾经了解到这么一个东西: 『听说过minecraft的边境之地吧,当你到达minecraft的很远的地方时,那里的区块会出现bug,也就是加载错误(32位溢出)。在java版中,这个bug早就已经在beta1.8版本移除(但没有完全移除,64位溢出导致的边境之地仍然存在),并添加了世界边界拦着你。当你以任何方式越过世界边界后来到外面,会得到一些负面效果,扣血死亡,就好像绝地求生里一样。其实java版的minecraft还真的有点像绝地求生,你还可以使用特定的指令修改边界,来达到绝地求生的效果。是不是很神奇?』 那用什么指令可以修改世界边界呢? 这条指令就是: \/worldborder worldborder这个单词虽长,但其实是由world(世界)和border(边境)这两个单词组成。所以,worldborder的意思是:世界边境。 \/worldborder 作用:管理世界边界 需要权限等级:java-2 需要作弊:是 版本独有:java版 格式: \/worldborder add <增减量:米>[过渡时间] \\\\将世界边界的边长增加或减少指定的值,可指定变化边长的过渡时间\\\\ \/worldborder set <边长:米>[过渡时间] \\\\将世界边界的边长设定为指定的值,可指定变化边长的过渡时间\\\\ \/worldborder center \\\\将世界边界的中心设置为指定地点,可使用相对坐标,但无法使用局部坐标\\\\ \/worldborder damage buffer <安全缓冲距离:米> \\\\设置玩家超出世界边界后,不受到伤害的安全缓冲距离\\\\ \/worldborder damage amount <伤害量> \\\\设置玩家超出世界边界外的安全缓冲距离后,受到伤害的情况,下面会具体讲解\\\\ \/worldborder warning time <提前警告时间> \\\\设置世界边界在变化过程中,如果边界经过玩家所在位置所剩的时间小于等于指定的时间,将会给予玩家警告\\\\ \/worldborder warning distance <警告距离> \\\\当玩家距离世界边界的距离小于此指定值时,将会出现警告\\\\ 在学习这指令的使用前,我们不妨具体来了解一下世界边界: 世界边界,是java1.8版本才出现的一个东西,用于防止玩家进入假区块,导致游戏崩溃或使得存档损坏。对于处于生存和冒险模式的玩家来说,可以在不作弊的情况通过一些bug逃出边境,但是逃出去一定距离后会受到伤害,最终死亡。 (这就是为什么minecraft从某方面来说具有开发吃鸡小游戏的潜力) 世界边界的屏障效果会在256格处消失,但是其作用会一直延续到y=2的31次方-1的地方,即y=的高度(int整形上限,讲nbt的值类型时会讲到)。 如果我们把整个minecraft地图都渲染出来,你就会发现世界边界其实是一个蓝色的正方形,正方形的中心位于世界原点(0.0,0.0),边长为.0米(格)。 而我们通过worldborder指令,就可以修改这个『蓝色正方形』的边长、中心位置和给玩家的效果。 首先,如果我们要修改边长,可以有两种方法:使用add或使用set。 add子命令可以增加或减少世界边界的边长,增加用正数,减少用负数。 如: \/worldborder add 11 就可以将世界边界的边长增加11米 \/worldborder add -10 就可以将世界边界的边长减少10米 set子命令可以直接将世界边界的边长设置为一个指定的值,比如: \/worldborder set 10 这将会将世界边界的边长设置为10米。 (注:你最大可以设置世界边界的边长到米) 虽然说add和set子命令是设置世界边界边长的,但确切来说,是设置蓝色『屏障』的边长。 ?这两个不是一摸一样吗? 其实世界边界由两部分组成:蓝色的虚假『屏障』,和隐形的真正屏障。 蓝色的虚假屏障并不能拦住玩家,真正能够拦住玩家的,是边长大于等于蓝色屏障的隐形屏障。 隐形屏障构成的隐形正方形,和蓝色屏障构成的蓝色正方形,虽然中心一样,但边长有时并不一样。隐形屏障的边长必须是一个偶数(或奇数,看中心点位置),因为它必须要处在方块的边缘,和方块的网格重叠。而蓝色屏障的边长可以是任意数,也就是说它不一定要处在方块的边缘,它是可以横着穿过边界方块的中点的。 也就是说,隐形屏障的边长必须大于等于蓝色屏障的边长。如果蓝色屏障的边长也是一个偶数(或奇数,看情况),那么两者的边长就一样,也就是互相重叠;但如果蓝色屏障的边长是一个奇数(或偶数,看情况),甚至是一个小数,那么隐形屏障的边长将会是大于蓝色屏障边长的最小偶数(或奇数,也要看情况)。 (其实你不知道也可以的,毕竟minecraft wiki又没记载这东西,这仅仅是作者实验得出的结果而已) 对了,还需要注意一点:使用set子命令时,当你设置的边长是一个大于(2的24次方)的奇数时,最终设置成的边长将会强制变为一个偶数。(java1.13.2作者实验得出) 为什么呢?可能是因为set子命令的『边长』参数其数据类型是单精度浮点数(下面的原因比较超纲,如果你有兴趣可以看一看),单精度浮点数只有24位的二进制有效数位,也就是说最大只能精确到,也就是2的24次方。对于大于的数字,比如,因为其二进制已经来到了25位,因此必须舍弃掉一些精度,也就是使得从25位开始的位数全部变为0。 在这边,舍弃精度有一个规则: 如果第25位是1,计算机会先看看更高位的情况。如果后面的位数有东西,那就进位(当然我们这边数值还不会达到那么大,因此不需要考虑这种情况)。如果后面没东西,还得看看第24位。如果第24位是0,那么就直接将从25位开始的数位全部变为0,也就是将高于24位的数位全部置零;如果第24位是1,那么也是进位。 比如,其二进制是。可以发现其第25位为1,后面没有更高的位数,24位还是0,因此就会将25位置零,变成,也就是。 又比如,其二进制是。可以发现其可以发现其第25位为1,后面没有更高的位数,24位也是1,因此就会进位变为,也就是。 需要注意,这个bug在最新版本已经被改掉了,只不过我们并不知道是哪个minecraft版本修复了这个bug。 回到正题。现在我们已经知道了如何改变世界边界的边长,但这个『过渡时间』又是什么? 在pubg也就是吃鸡游戏中,毒圈也会像minecraft的世界边界一样变小,但前者可以慢慢地收缩,那后者呢? 也可以。你只需要指定『过渡时间』就可以了。 过渡时间参数的单位为秒,如果指定了它,那么游戏将会在规定的时间内慢慢地将世界边界的半径从原来的值调整为新指定的值。比如: \/worldborder add -100 60 这将会使得世界边界在1分钟内半径慢慢减少100格。收缩过程中,世界边界将会变成红色。如果是放大的话,将会变为绿色。 如果你后悔了想要暂停变化该怎么办? 你得使用add或set子命令,重新改变一下其边长,并且不能填写过渡时间参数,然后世界边界就会暂停变化,立马变为你设置的边长。 这里有一个有趣的东西,如果你使用的是add子命令,那么增加或减少的边长并不是以变化开始前的边长为基准,而是以你运行add时其变化到的边长为基准。 举个例子,假设此时世界边界的边长为200米,你用了\/worldborder add -60 60使得世界边界将会在60秒内收缩至140米。如果你过了13秒突然反悔,用了\/worldborder add 60来放大世界边界,那么最终世界边界的边长将会变成247米。 为何呢?因为在你等待的13秒内,世界边界已经收缩了13米,到了187米。此时你再使其增加60米,由于你未填写过渡时间参数,过渡时间就会被重置为立刻,但游戏却会以现在的187米为基础来计算增加60米后的半径,也就是247米。最终,你就会收到如下信息: 已将世界边界的宽度设为247.0 既然未填写过渡时间参数就会重置原先的过渡时间,那么如果再填呢?也就是运行\/worldborder add 60 60会发生什么? 答案是:原先剩下的47秒过渡时间会和新加的60秒过渡时间相加,最终你会收到如下消息: 正在将世界边界的宽度扩大为247.0个方块,时间107秒 没想到就那么简简单单的set和add两个子命令,能够有这么复杂的效果啊...... 放心,接下来就简单了。 使用\/worldborder get可以获取到当前世界边长的信息,这就不多讲了,因为没啥好讲。 center子命令可以设置世界边界的中心,比如使用: \/worldborder center 1 1 这将会设置世界边界的中心为(1.5,1.5)。 唉怎么回事,我不是要设置到(1,1)吗?怎么设置到(1.5,1.5)去了? 如果你仔细观察一下,就会发现不仅仅在worldborder指令中有这个现象,很多指令中也有这个现象。 背后的原因其实令全球变暖:mojang官方认为你填整数就是要将中心设置在一个方块的位置上,而我们人类主观上来看,方块的位置就是这个方块的中心,因此mojang就贴心地给你加了个0.5。 如果你并不想让mojang帮你加上0.5,很简单,运行:\/worldborder center 1.0 1.0即可,也就是加上小数点,弄成一个浮点数。其他指令如果出现类似情况也可以这么弄。 需要注意,在某些minecraft java版本中,center的坐标参数是可选的。但根据作者的测试,1.8、1.12.2、1.13.2、1.16以及最新的1.19版本的坐标参数均为必填,所以我们并不清楚哪些版本的center坐标参数是可选的,也许是一些快照版本也说不定。 对于坐标参数是可选的版本,使用\/worldborder center可以获取到世界边界中心的位置。(所以mojang,这么好的功能你为什么不加呢?) 我们现在已经会操控世界边界的大小以及位置,但别忘了,世界边界还可以对『出圈』的玩家造成伤害! 我们可以通过damage子命令来更改世界边界的伤害: \/worldborder damage buffer <安全缓冲距离:米> \/worldborder damage amount <伤害量> 安全缓冲距离指的是玩家『出圈』后,不会受到伤害的『出圈』距离,默认是5米,你可以改为一个大于等于0的数值。比如: \/worldborder damage buffer 1.5 这将会指定『安全缓冲距离』为1.5米,玩家如果『出圈』且与世界边界的距离超过1.5米,将会开始受到伤害。 damage amount可以指定玩家超出缓冲距离受到伤害的情况,默认其值是5.0。但这并不是指玩家超出后每秒受到的伤害是5.0点,而是有一个更加复杂的计算。 玩家每秒受到的伤害大小y其实和玩家远离缓冲区的距离x成正比例关系,其比值k就是我们damage amount所规定的『伤害量』参数,更确切的来说是『每方格伤害量』参数: 玩家每秒受到的伤害大小=每方格伤害量x玩家远离缓冲区的距离(每方格伤害量≥0) y=kx (k≥0) (只不过如果每方格伤害量被设定为0的话,也就是不造成伤害,那就构不成正比例函数了) 比如我们设定伤害量为0.2点\/米\/秒,缓冲区为1.5米。有一名玩家超出了世界边界15.7米,那么这名玩家每秒受到的伤害量将会是: 0.2x(15.7-1.5)=2.84点\/秒 最后,我们可以设定一些效果让这个世界边界看起来更像是『毒圈』。比如,我们可以设定警告。 warning子命令就是干这个的: \/worldborder warning time <提前警告时间> \/worldborder warning distance <警告距离> 『提前警告时间』的单位为秒,默认是15秒。玩家如果将要被世界边界越过,且距离被越过剩下的时间小于等于『提前警告时间』,玩家就会被游戏警告,也就是屏幕会被染红。 『警告距离』就更好理解了,其默认是5米。如果玩家离世界边界的距离小于等于『警告距离』,玩家也会被游戏警告。 比如: \/worldborder warning time 20 就可以使玩家在被世界边界越过的最后20秒内收到警告。 最后,我们会发现世界边界已经被我们玩得不成样子了。 那怎么办呢? 运行\/worldborder set ,即可将世界边界弄回到最初的大小。 运行\/worldborder center 0.0 0.0,即可将世界边界的中心点弄会最初的位置。 历史 1.8——加入了\/worldborder和世界边界 第六十六章 指令大杂烩 本章整理了一些比较有用但很简单、篇幅不长的指令。 第一个——\/teammsg(\/tm)——minecraft里的『队伍频道』 存在版本:java1.14-今 别名:\/tm 需要权限等级:0 需要作弊:否 命令方块兼容性:由于命令方块无法被添加进队伍,因此无法执行 格式: \/teammsg <信息> \/tm <信息> 用法\/效果: 这可以使得命令执行者给全体队员发送一条消息,也就是在minecraft中的『队伍频道』中发送消息。需要注意,命令执行者必须归属于一个队伍,并且不能是个命令方块甚至是服务器控制台,也就是说必须是一个实体。 第二个——\/daylock(\/alwaysday)——控制昼夜循环 存在版本:基岩版1.2.0-今 别名:\/alwaysday 需要权限等级:1 需要作弊:是 格式: \/daylock [锁定昼夜更替:布尔值] \/alwaysday [锁定昼夜更替:布尔值] 用法\/效果: 如果『锁定昼夜更替』参数为true,则使得游戏时间不会流动,并保持白日(就是打开了设置界面的『终为白日』并关闭了『开启昼夜更替』。如果为false则使得游戏时间回归原来的样子,即流动状态。如果未填写则默认为true,即锁定昼夜更替。 第三个——\/difficulty——查询或改变游戏难度 存在版本:java1.4.2-今|基岩版1.0.5-今 需要权限等级:java-2 基岩-1 需要作弊:是 格式: \/difficulty [难度id] 用法\/效果: 如果未填写难度id,可以查询当前游戏的难度。 难度id可以填写难度的id全称、简称和数字id。对于java1.13及以上版本,只能填写难度id的全称。 难度id如下: 难度名称—全称—简称—数字id 和平—peaceful—p—0 简单—easy—e—1 普通—normal—n—2 困难—hard—h—3 例子: \/difficulty e ——在java1.13以下版本和基岩版中,这条指令可以将游戏难度改为简单。对于java1.13及以上版本,需要运行\/difficulty easy才能达到同样的效果。 第四个——\/mobevent——查询或控制允许运行的生物事件 存在版本:基岩版1.11.0-今 需要权限等级:基岩-1 需要作弊:是 格式: \/mobevent <事件名称>[允许运行:布尔值] 用法\/效果: 这条指令很像gamerule,唯一的区别是前者是控制游戏规则,后者是控制生物事件。 截止基岩版1.19版本,这条指令支持控制4个生物事件: minecraft:ender_dragon_event——控制初次进入末地时是否生成末影龙。 minecraft:piger_patrols_event——控制生成灾厄巡逻队。 minecraft:wandering_trader_event——控制是否生成流浪商人。 events_enabled——控制是否开启事件子系统。 如果未填写『允许运行』参数,可以查询指定的事件是否被允许运行。 『允许运行』参数可以填写true和false。如为true则允许事件运行,false则禁用事件运行。 events_enabled可以控制整个事件系统。如果禁用它,所有单独事件将不会运行。如果启用,仅仅被单独禁用的事件将不会运行。 例子: \/mobevent minecraft:wandering_trader_event false 这条指令可以禁止流浪商人的生成。 \/mobevent events_enabled false 这条指令将禁止所有单独事件运行。 第五个——\/defaultgamemode——设置默认游戏模式 存在版本:java1.3.1-今 需要权限等级:2 需要作弊:否 格式: \/defaultgamemode <游戏模式id> 用法\/效果: 用法和\/gamemode类似,这里就不多讲了。 这条指令可以控制新进入游戏玩家的默认游戏模式。 需要注意,对于服务器来说,如果服务器配置文件server.properties中的force-gamemode选项被开启(true),那么所有玩家都会被强制更改为此指令设定的模式。 例子: \/defaultgamemode adventure 这将会使得接下来新进入游戏的玩家的默认游戏模式为冒险模式。 第六个——\/publish——开放单人游戏世界 存在版本:java1.3.1-今 需要权限等级:4 仅单人游戏:是 格式: java1.13更新前 \/publish java1.13及更高版本 \/publish [端口] 用法\/效果: 相当于在暂停界面点击『对局域网开放』,也就是将本地的单人游戏在局域网上开放。对于java1.13及以上版本来说,可以设定开放的端口(至少比直接在暂停界面设置强多了)。 端口必须是一个介于0~的整数。如果未指定,游戏会随机选取一个大于1024的端口。 例子: \/publish 这将会使得单人游戏公开到局域网,并占用端口进行通信。 第七个——\/recipe——给予或剥夺合成配方 存在版本:java1.12-今 需要权限等级:2 需要作弊:否 格式: \/recipe (give|take)<目标玩家><物品id> 用法\/效果: 这条指令有两个子命令:give和take。give可以给予目标玩家指定的合成配方,take就是剥夺目标玩家的合成配方。 『物品id』参数即具体要剥夺的合成配方对应的物品id。比如指定minecraft:pass(指南针),就可以给予或剥夺目标玩家的指南针合成配方。这个参数也可以直接填写星号『*』来代指所有合成配方。 (这条指令真的是没什么存在感,能用到的地方太少了) (当然,如果启用dolimitedcrafting游戏规则,即玩家只能使用已经解锁的合成配方来合成物品,那么这条指令瞬间就会变得十分有用) (这么说的话,一个新玩法就出来了!) 例子: \/recipe give @s minecraft:pass 这将会给予指令执行者(也就是你自己)指南针的合成配方。 \/recipe take @a * 这将会剥夺所有玩家的所有合成配方。 第八个——\/setmaxyers——设置多人游戏玩家人数上限 存在版本:携带版1.1.0-今 需要权限等级:3 需要作弊:是 格式: \/setmaxyers <玩家人数上限> 用法\/效果: 这条指令可以设置基岩版多人游戏的玩家人数上限,最大支持30人。 『玩家人数上限』参数的值如果小于当前在线的人数或大于服务器最大支持的连接数量,游戏将会修正人数上限到上述范围内。 只不过,作者三四年前曾经用过这条指令在网易我的世界尝试提高联机模式的人数,但并没有效果。所以你如果想到似乎能够这么用,那你就别想了,网易已经帮你想到了。 例子: \/setmaxyers 20 不出意外的话,这将会设置当前多人游戏的玩家数量上限为20人。 最后一个——\/spectate——控制旁观模式玩家的视角 存在版本:java1.15-今 需要权限等级:2 需要作弊:否 格式: \/spectate <要附身的对象>[玩家] \\\\使目标玩家或执行者自己(必须处于旁观者模式下)的视角附身在指定的对象上,对象必须是单个玩家或实体\\\\ \/spectate \\\\使得执行者自己不再将视角附身于指定的对象上\\\\ 用法\/效果: 上面列格式时已经说了。 例子: \/execute as @a[gamemode=spectator] run spectate @p[distance=0.1..,gamemode=!spectator]@s 这将会使得所有处于旁观者模式的在线玩家附身到距离自己最近的一名不处于旁观者模式的玩家身上。 第六十七章 更高级的locate (此章节于2022年7月13日重写) 近日,mojang在minecraft java1.19.1版本中添加的yer reporting system(玩家举报系统)引起了轩然大波,许多minecraft玩家认为这是minecraft将要走向下坡路的前兆。 但这和我们暂时没有关系,相反,1.19荒野更新中的一些关于指令的更新更需要得到我们的注意。比如1.19版本中,mojang对指令\/locate的更新。 在第二十一章,我们了解到了\/locate指令的用法,也就是如下: java1.19版本前 \/locate <结构名> 基岩1.19.10版本前 \/locate <结构名>[仅在未生成的区块中查找:布尔值] 看起来相当的简单,mojang也这么认为。但mojang不只是认为这条指令简单,他们还认为这条指令简单到过于简陋。于是,在minecraft java1.19和minecraft bedrock edition 1.19.10更新中,mojan对\/locate指令进行了大更新,变成了如下模样: java1.19及之后版本 \/locate biome <生物群系id> \/locate poi <兴趣点id> \/locate structure <结构id> 基岩版1.19.10及之后版本 \/locate biome <生物群系id> \/locate structure <结构id>[仅在未生成的区块中查找:布尔值] (注:基岩版的locate尚在更新中,有可能会发生变化) 看起来仍然相当的简单。 首先,\/locate原来的功能,也就是『定位特殊的建筑(结构)』,被移植到了structure子命令中,这里我们就不细讲了。然后,mojang将\/locatebiome这条指令合并到了\/locate,变成了biome子命令。最后,mojang添加了一个新的子命令,叫做poi,可以用于查找兴趣点。 唉,什么是兴趣点?它有什么用?为什么会让我们兴趣? 待会我们会讲到,先让我们来看看这个\/locatebiome命令又是什么。 \/locatebiome 作用:寻找指定生物群系 存在版本:java1.16-1.19快照 需要权限等级:2 需要作弊:否 格式: \/locatebiome <生物群系id> \/locatebiome这条指令添加于1.16版本,其功能类似于当时的\/locate指令,可以查找最近的生物群系并返回其位置。 也是很简单,但功能由于和locate太类似,mojang就让它合并过来了。 现在我们再来看看poi子命令。 上面说了,poi子命令可以查找兴趣点。兴趣点是什么? 兴趣点(point of interest),是在minecraft java 1.14加入的一个东西,主要指的是能被村民或其他生物认领的方块(注:这是作者自己的定义,官方目前没有给出定义)。也就是说,并不(只)是你会对这东西感兴趣,而是村民以及其他的一些生物会对这东西感兴趣。 有哪些方块是兴趣点呢? 截止目前(java1.19.1),有如下兴趣点: \\\\能被村民认领的\\\\ 高炉(armorer) 烟熏炉(butcher) 制图台(cartographer) 酿造台(cleric) 堆肥桶(farmer) 木桶(fisherman) 制箭台(fletcher) 床(home) 炼药锅(leatherworker) 讲台(librarian) 切石机(mason) 钟(meeting) 织布机(shepherd) 锻造台(toolsmith) 砂轮(weaponsmith) \\\\跟蜜蜂有关的\\\\ 蜂巢(bee_nest) 蜂箱(beehive) \\\\跟玩家有关的\\\\ 避雷针(lightning_rod) 磁石(lodestone) 下界传送门her_portal) 举个例子。比如我们要寻找最近的下界传送门,就可以运行如下指令: \/locate poi minecrafther_portal 蛮简单的,这个兴趣点看起来好像很高大上,实际上也没什么嘛。 现在,新版本的\/locate算是介绍完了。但还有一些问题: 在java新版本中,各种村庄的id被拆分了,虽然这对我们搜索特定种类的村庄有很大帮助,但万一我们仅仅只是想找个村庄该怎么办? 答案很简单:用标签。 还记得我们在『本书第一次大修新增章1』中提到的标签吧?在minecraft java 1.18.2更新中,mojang开始允许\/locate和\/locatebiome指令使用标签进行查找,就算\/locate经过了如此大的更新,这个功能也没砍。 那有哪些标签,怎么使用呢? 对于结构来说: cats_spawn_as_ck(会生成黑色的猫) cats_spawn_in(会生成猫) dolphin_located(会有海豚) eye_of_ender_located(会有末地传送门) mineshaft(是矿井) ocean_ruin(位于海里的废墟) on_ocean_explorer_maps(在海洋探险家地图上的) on_treasure_maps(在宝藏地图上的) on_woond_explorer_maps(在林地探险家地图上的) ruined_portal(是破败的传送门) shipwreck(是船的废墟) vige(是村庄) 对于生物群系来说: 非常多,不列了,自己去minecraft wiki上查 对于兴趣点来说: acquirable_job_site(村民的工作站) bee_home(蜜蜂的家) vige(跟村庄有关的) 比如,我们要查找最近的村庄,我们可以这么做: \/locate #minecraft:vige (java1.18.2) \/locate structure #minecraft:vige (java1.19及之后) 我们要查找最近的山地类生物群系,我们可以这么做 \/locatebiome #minecraft:is_mountain (java1.18.2) \/locate biome #minecraft:is_mountain (java1.19及之后) 那么本章就到这里了。接下来,我们将正式开始学习execute的使用。 第六十八章 新版execute的变化 (本章节于2022年7月14日重写) 在第三十三章,我们了解了java1.13更新前的和基岩版的execute指令的使用,让我们复习一下: 格式(基岩版、java1.13更新前): \/execute <执行者:目标选择器><基准点:坐标><执行的指令> \/execute <执行者:目标选择器><基准点:坐标> detect <探测的坐标><方块id><方块数据值><执行的指令> 看起来相当简单,就连幼儿园大班的孩子都会用。我们马上就可以根据上面的格式,举一个小小的例子: \/execute @e[type=zombie]~~~ detect 36 71 202 redstone_block -1 tp @s @p 这条指令的意思是:将所有僵尸作为执行者,他们所处的位置作为执行地点,如果坐标(36,71,202)处的方块为任意数据值的红石块,就将每个僵尸分别传送到距离它们最近的玩家。 但java1.13更新后的execute呢?还有目前(2022\/7\/14)基岩版1.19.10版本在测试中的execute呢?这些新版本的execute有何变化? 答案是很大的变化。由于目前基岩版的execute命令还在测试中,并且功能比java版要少且类似,我们就先不了解。 在java1.13更新中,execute的语法被彻底重写,最终变成了四类12条子命令:修饰子命令(8条)、条件子命令(2条)、存储子命令(1条)和run子命令(运行子命令)(1条)。 正如这四类子命令的名字,它们的功能分别是: 修饰子命令——对指令进行修饰,也就是对执行指令的一些基本条件进行修改,也就是更改指令执行者、执行地点、执行朝向等内容。 条件子命令——就像编程中的if,如果条件成立才会执行指令。 存储子命令——还记得之前讲到的\/stats指令吗?在java1.13更新后,它的功能就被合并到了execute中,作为存储子命令,而且还升级了!不光能够将指令执行的结果存储到计分板中,还能存储到其他地方去! run子命令(本书称为运行子命令)——也就是最终execute要运行的指令 这四种12条子命令可以自由组合,但有些详细的规则我们会在以后了解到。 看起来这12条子命令很多,但其实它们中的大多数我们都已经在前面遇见过了,因为新版本的execute把许多独立的指令给合并掉了。如果你前面的章节有细心看的话,那么你应该能够列出execute吃掉了哪些指令: \/stats(获取并存储指令执行结果) \/testfor、\/testforblock、\/testforblocks(检测方块、实体) \/scoreboard yers test子命令(检测分数) 你可以猜一猜上述指令被execute吃掉后变成了哪一类execute的子命令,我们下一章就会开始正式的学习过程。 第六十九章 修饰子命令 上 三要素与修饰子命令 (于2022\/7\/14重写) 在第七章,我们总结出了指令执行的三要素:执行者、执行位置和参数。 但在经过了六十几章的学习后,我们会发现,这三要素似乎有点不对啊? 哪里不对呢? 执行者肯定会有,就算没有也会有默认值;执行位置肯定也会有,并且它照样也有默认值。 但参数呢? 虽然有些参数也有默认值,但有些指令它根本就没有参数啊!比如\/seed指令,根本就不需要参数。 所以在这,我们必须纠正一个已经持续了几十个章节的错误,那就是: 参数并不是指令必须要有的东西,它不算是指令执行的要素。 那照这样子说,我们的三要素是不是就要变为二要素了? nononono。三要素还是三要素,虽然参数不是了,但有一个一直以来都在被我们忽略的东西能够被当作是指令执行的三要素。 什么呢?难不成是目标选择器的基准点? 答案是:执行朝向。 执行朝向是一个神奇的东西。我们第一次遇见它在第九章,花了较长的篇幅讲解了水平旋转角度和垂直旋转角度;第二次遇见它在第二十六章,又讲了一遍水平旋转角度;第三次遇见在第六十四章,花了较长的篇幅讲解了相对旋转角度和基准部位;接下来,我们可能还要再次遇见它,讲解它和局部坐标的关系。 不难发现,相对于执行位置、执行者,我们却很少遇见执行朝向。但每次执行朝向一出现,我们就得花大量的笔墨去讲解它。所以说,执行朝向是指令执行三要素中最难理解的部分,它不仅仅只是一个朝向那么简单,它还关系到许许多多的东西。 现在,我们总结出了新的指令执行三要素:执行者、执行位置和执行朝向。其中,执行位置还包括维度和坐标;执行朝向包括旋转角度和基准部位。而这些东西,我们都可以通过新版execute的8条修饰子命令来自定义: as ——更改执行者 at ——更改执行位置(包括维度和坐标)和旋转角度为指定实体的位置和旋转角度 facing ——更改旋转角度 rotated——更改旋转角度 anchored——更改基准部位 positioned ——更改执行位置中的坐标 in ——更改维度位置 align——将执行位置中的坐标转化为方块坐标 这一章,我们就先讲几个简单的:as、at和in。 as子命令可以更改执行者,类似于旧版的『执行者』参数,但其仅仅只会更改执行者,而旧版的『执行者』参数还会更改旋转角度。 as子命令的使用十分简单,如下: ... as <执行者:目标选择器>... 举个例子: \/execute as @a run 一条指令 (run子命令虽然我们没有讲过,但其实你应该也懂了,『run +命令』就可以运行指令) 这将会将指令执行者更改为所有玩家自身,指令在运行时会分别将每个玩家作为执行者运行一遍。唉,什么叫『指令在运行时会分别将每个玩家作为执行者运行一遍』呢?,之前讲旧版的execute时可从未提到过啊? 举个小小的例子,你就知道了: \/execute as @e[type=viger] run scoreboard yers add viger_count an_objective 1 假设viger_count这个假玩家在计分项an_objective上的分数原先为0。请你猜一猜,运行这条指令过后,分数将会变为多少?一定会变为1吗? 上面这条指令的意思是:将所有村民作为执行者,给viger_count在计分项an_objective上的分数加上1。而指令在运行过程中,会将每位村民都作为执行者运行一遍指令,因此最终指令将会运行『村民总数量』遍,我们也成功地将村民的总数量作为分数记到了计分板上。假设现在有两名村民,最终得到的分数将会是2,因为这两个村民都分别运行了一遍『scoreboard yers add viger_count an_objective 1』。 为什么指令在运行过程中,会将每位村民都作为执行者运行一遍指令,而不是直接将所有村民作为执行者,仅仅运行一遍指令? 原因很简单:每条指令执行过程中,执行者、执行位置、执行朝向分别都只能有一个。 请你一定要记住这个知识点,因为接下来我们将会需要运用这个知识点来解决一些问题。 对了,既然新版本的execute有这个特性,那旧版本呢? 也是有的。 所以你能想到这有什么用处吗? testfor指令虽然可以用来探测指定实体是否存在,但想要将数量储存到计分板中还需要一个\/stats指令,十分麻烦且容易出错。而execute如果这样用,直接吊打testfor啊!而且,这是可以用于基岩版的,做玩家人数检测或实体数量检测! 比如在基岩版,你可以这么干: \/execute @a[r=10,x=15,y=94,z=20,tag=游戏参与者]~~~ scoreboard yers add yer_count count 1 这将会计算出以(15,94,20)为中心,半径10米内带有『游戏参与者』标签的玩家数量,非常适合用于小游戏的人数判定。 回到正题啊,接下来我们来看看at子命令。 at子命令,可以更改执行位置中的维度位置、坐标以及执行朝向中的旋转角度为指定实体的维度位置、坐标和旋转角度。其格式也是十分滴简单: ... at <实体:目标选择器>... 举个例子: \/execute at @e[type=minecraft:arrow] run summon viger ~~~ 这将会在每支箭的位置,分别运行一遍『summon viger ~~~』来召唤一只村民。 可以发现,虽然我们没有更改执行者,但相对坐标的基准点却被更改了,这说明相对坐标默认不是将执行者的位置作为基准点的,而是将指令执行位置作为基准点。其实这个我们在第五章就已经提到了,这里只不过再提一下而已。 另外,你有没有注意到『分别』两个字?也就是说,at子命令照样会使得指令在每个位置分别运行一遍。不要小看这一点,待会你就会知道小看这一点会导致什么严重的灾难。 in可以更改指令执行的维度位置,因此我们可以通过in指令来快速前往其他维度。其语法如下: ... in <维度id>... 举个例子: \/execute in minecraft:theher run tp @s ~~~ 这将会把你传送到地狱。需要注意的是,你的x和z坐标可能会被除以8。比如你原先的坐标是(16,80,16),传送到下界后估计就会变成(2,80,2)。 为什么呢?如果你有一点mc常识的话,你就会知道,在大多数minecraft版本中,下界中的1米相当于主世界的8米,所以自然而然,你从主世界传送到下界,x和z轴就会除以8(可以通过添加其他子命令来避免这种情况)。 但在java稍微旧一些的版本中,运行上述指令并不会改变你的坐标,也就是说不会除以8,还是会保留你原先的(16,80,16)。这是作者在1.14.4版本中发现的,但在最新的1.19版本中不会出现这种情况,因此应该是在1.14.4~1.19间的某个版本修复了这个bug。作者猜测可能是1.16更新,只不过懒得去测试了。 另外还需要注意,在1.18及更高版本中,虽然主世界的y坐标向下延伸到了-64,但其他维度并未变化,因此如果你从y坐标小于0的地方直接传到地狱或其他维度,极有可能会掉进虚空! 现在我们来尝试一下结合上面的三个子命令+run子命令,看看当多条子命令结合起来时会有什么效果。 我们来试着将所有实体往上抬1米: \/execute as @e at @e run tp @s ~~1 ~ 运行之后,你会惊喜的发现,所有实体都往上抬了1米,但也都传到了同一个地方,甚至有些实体还被挤死了。 这是怎么回事? 这就是为什么我在前面一直提醒着你说at和as都会在每一个实体和每个位置运行一遍指令。 让我们来逐步分析一下上面的指令出了什么bug,也就是模拟一下游戏运行这条指令的过程。 假设现在整个世界仅仅只有3个实体:一名玩家(最早生成),一位村民和一只羊(最晚生成)。 当这名玩家敲下回车键将指令发送给游戏时,游戏开始对这条指令进行解析并运行: as子命令让游戏知道,接下来要改变执行者。而目标选择器@e选择了这三个实体,并使得它们按照生成时间的早晚排序,因此游戏根据as @e,先选择了这名玩家作为执行者,然后再选择村民,最后选择羊。 接下来游戏看到了at @e,由于之前已经选择好了执行者,所以游戏根据上文还有这里,得知这名玩家将会依次在玩家的位置、村民的位置和羊的位置分别运行一遍指令,村民和羊同理。 最后游戏看到了run以及后面的指令,它已经完全明白接下来要干什么事情了: 1将玩家传送至玩家上方1米的位置(玩家此时抬高了1米) 2将玩家传送至村民上方1米的位置(玩家此时位于村民上方1米) 3将玩家传送至羊上方1米的位置(玩家此时位于羊上方1米) 4将村民传送至玩家上方1米的位置(村民此时位于玩家原本位置上方1米,玩家此时位于羊上方1米) 5将村民传送至村民上方1米的位置(村民此时位于村民原本位置上方1米,玩家此时位于羊上方1米) 6将村民传送至羊上方1米的位置(村民和玩家此时位于羊上方1米) 7将羊传送至玩家上方1米的位置(村民和玩家此时位于羊原本位置上方1米,羊位于玩家原本位置上方1米) 8将羊传送至村民上方1米的位置(村民和玩家此时位于羊原本位置上方1米,羊位于村民原本位置上方1米) 9将羊传送至羊上方1米的位置(村民、玩家和羊此时都位于羊原本位置上方1米) 最终,三者都跑到了羊原先位置上面1米处,指令运行了3x3=9遍。 太离谱了是不是?但既然写两个@e会造成混乱的话,那么该怎样写呢? 因为第一个as子命令已经更改了执行者,后面的子命令都会按照更改后的来,所以我们只需要: \/execute as @e at @s run tp @s ~~1 ~ 将at的@e改为@s即可。 或者说把at放前面,曲线救国一下: \/execute at @e as @e[limit=1,sort=nearest] run tp @s ~~1 ~ 这也是可以的。 所以在execute中,各个子命令的顺序十分重要,每个子命令都会影响到后面的子命令。希望你能记住这一点,不然可能会犯一些就像上面这样的严重错误。 我们再来试试结合in和at两个子命令,看看当两个子命令所影响的范围有重合时会发生什么: \/execute at @s in minecraft:theher run tp @s ~~~ \/execute in minecraft:theher at @s run tp @s ~~~ 你可以猜一猜,当你运行这两条指令时,效果分别是怎样的? 首先,第一条指令的效果和之前『\/execute in minecraft:theher run tp @s ~~~』的效果不能说十分相似,只能说是完全一样。at子命令将执行位置和朝向设定为了你的位置和朝向,但由于本来就是这样所以可以去掉。in虽然仅仅会影响到维度,但如果像是地狱这种特殊的维度,在影响到维度位置的同时,in也会对当前的坐标进行设置。所以说是完全一样,并不会说你这样设置可以将你传到地狱而不改变坐标的。 而第二条指令就更不用说了,in刚刚把维度改过去,at又改了回来,所以第二条子命令相当于『\/tp @s ~~~』,把自己传送到自己的位置,实际上没有任何效果。 所以说,execute就像是个流水线,指令的三要素从指令开头出发,依次经过各个修饰子命令的洗礼,最终在run子命令『出厂』。采用这种『流水线思维』,我们才能更好地理解更加复杂的execute命令。 本章到此结束。 第七十章 修饰子命令 下 剩下的5个修饰子命令 (于2022\/7\/15重写) 在上一章,我们总结出了新『指令执行三要素』,并初步学习了修饰子命令中的『as、at和in』子命令,了解了execute的『流水线思维』(注:这个思维名称是作者自己编的)。那么接下来我们就应该快马加鞭,看看剩下的五个修饰子命令: facing ——更改旋转角度 rotated——更改旋转角度 anchored——更改基准部位 positioned ——更改执行位置中的坐标 align——将执行位置中的坐标转化为方块坐标 我们先从前几章在讲tp指令就接触过的facing子命令入手: (?怎么就接触了?) (因为两者非常像,算接触也可以啊) execute的facing子命令,和tp\/teleport指令的facing参数十分类似,都是『改变朝向为面向指定的坐标或某个实体』,只不过前者改变的是命令的执行朝向,后者改变的是传送目标的朝向。 所以facing子命令的语法相比tp的facing语法,不能说是十分类似,至少也是一模一样了: ... facing <坐标>... ... facing entity <实体><朝向部位>... 是不是?也就『朝向部位』这个参数从可选变成了必填而已。 既然功能都完全一样,这里也就不多介绍了,直接上例子: \/execute facing ^5 ^^ run tp ^^^ 这条指令是什么意思呢?它竟然有两个局部坐标! 但这两个局部坐标的朝向并不一致。第一个局部坐标的朝向和执行者的朝向一致,所以facing ^5 ^^在这的意思是『改变执行朝向为面向执行者左边5格』,第二个局部坐标的朝向和facing子命令指定的朝向一样,所以最终你将会看向你原本左边5格的位置。 \/execute facing entity @e[distance=1..,sort=nearest,limit=1] feet run tp ^^^ 这条指令将会使得执行者看向最近实体的眼睛。至于为什么是眼睛,我们已经在第六十四章讨论过了。 如果我们要实现看向最近实体的脚该怎么办? 想一想,当你看向一个人的脚时,你是用什么看的? 眼睛啊! 所以说,我们得把局部坐标的基准点从默认的脚部改到眼睛的位置,也就是更改执行朝向的基准部位。这时候,我们就需要用到anchored(\/???k?r\/)子命令。 anchored子命令的用法十分简单: ... anchored <实体锚点>... 其中,『实体锚点』参数也就是『基准部位』参数,前者是官方的叫法,后者是本书的叫法。它仅仅可以填写两个东西:eyes和feet。执行指令时默认是使用feet,这里我们尝试填写为eyes: 让我们试一试: \/execute anchored eyes run tp @s ~~~ facing entity @e[distance=1..,sort=nearest,limit=1] feet 这条指令可以使得执行者看向最近实体的脚部(从执行者的眼睛看向最近实体的脚部)。 更改执行指令的基准部位后,就会有一些有趣的效果。比如: \/execute anchored eyes run tp @s ^^^ 这将会将你传送到你眼睛的位置,更确切地说是将你的脚传送到你眼睛的位置。 facing可以更改旋转角度,但rotated子命令也能,那它俩有什么区别呢? rotated子命令并不是将执行朝向改为朝向某个地方,而是直接更改旋转角度为指定的旋转角度,或某个实体的旋转角度。其语法如下: ... rotated <水平旋转角度><垂直旋转角度>... ... rotated as <实体>... 这有点类似于tp指令的部分功能,execute相当于把这部分功能独立了出来(tp:怎么又是我)。 举个例子: \/execute rotated 270 0 ... \/execute rotated -90 0 ... 这两条指令都可以将执行朝向改为水平朝向正东方,只不过前者是采用我们在第九章教的『真南方位角』,后者是采用minecraft中标准的方位角。 \/execute rotated as @e[sort=nearest,limit=1]... 这将会使执行朝向与距离执行地点最近的实体一致。 十分简单,是不是?但请注意,和as、at子命令一样,当facing entity和rotated as选择到多个实体时,指令都会在每一种情况下分别运行一遍。 现在,at、facing、rotated、anchored这四个与旋转角度有关的子命令已经全部讲完了,剩下的两个子命令positioned和align仅仅和执行位置中的坐标有关系。让我们继续学习一下。 positioned子命令乍一看和at子命令很像,都是改变执行位置,但其实两者的区别很大。 positioned ——仅仅只能修改执行位置中的坐标 at ——不仅仅能修改执行位置中的坐标,还可以修改维度位置和旋转角度。 记住两者的区别之后,让我们来看看positioned子命令的使用方式: ... positioned <坐标>... \\\\修改执行位置中的坐标为指定坐标\\\\ ... positioned as <实体>... \\\\修改执行位置中的坐标为指定实体的坐标,如果有多个实体,则分别以每个实体的坐标作为执行位置的坐标,多次运行指令\\\\ 还是很简单,让我们来试一试: \/execute positioned 1 1 1 run tp @s ~~~ 这将会把你tp到(1.5,1,1.5)的位置。至于为什么不会tp到(1,1,1)处,我们在前几章已经讲过了。 \/execute positioned as @e[type=viger] run setblock ~~-1 ~ minecraft:diamond_block 这条指令将会在每名村民的脚下放置一个钻石块。 但还是请注意,positioned仅仅只会修改执行位置中的坐标。 为什么我要多次强调这个东西? 举个最简单的例子,假设你在下界,主世界有一个村民位于(1,23,1)的位置,此时你在下界运行一遍上面的指令,你就会发现: 在下界的(1,22,1)处,放置了一个钻石块,但理想情况下应该是在主世界放置。 这是怎么回事?答案很简单:因为positioned只会修改坐标,不会修改维度。如果你真的要使得在下界也能够让主世界的村民脚下生钻,有两种方法: 1\/execute as @e[type=viger] run setblock ~~-1 ~ minecraft:diamond_block \\\\将positioned as替换为as\\\\ 2\/execute positioned as @e[type=viger] in minecraft:overworld run setblock ~~-1 ~ minecraft:diamond_block \\\\加上in子命令,指定维度位置是主世界\\\\ 最后,我们只剩下了一个修饰子命令:align align这个子命令比较特殊,它并不是说修改维度位置为某个实体所处的维度,也不是说修改旋转角度为某个方块的朝向,而是对执行位置中的坐标小修小补:对小数向下取整,对整数保留不变,将坐标改为方块坐标。其语法如下: ... align <坐标组合>... 其中,『坐标组合』参数可以填写任意的xyz。注意啊,这里不是填写具体的数字,而是就填写xyz这三个字母的任意组合,甚至缺个x缺个y之类的都可以,只是不能重复而已。 比如: \/execute align xyz run tp @s ~~~ 假设你原本的坐标是(-105.315,-57.,-25.875),使用上述指令后你会传送到(-106,-58,-26),也就是将你的xyz三个坐标分别向下取整再传送。 上面这条指令你也可以写成: \/execute align yzx run tp @s ~~~ \/execute align zxy run tp @s ~~~ 都可以,就是不能这么写: \/execute align 1 1 1 run tp @s ~~~ \/execute align xxyyzz run tp @s ~~~ 这样子是不行的。 如果你只想对x坐标和z坐标进行向下取整,只需要去掉一个y就可以了: \/execute align xz ... 现在,8条修饰子命令都已经学完了,让我们来将它们一齐运用一下: \/execute in minecraft:theher positioned as @s run tp @s ~~~ 这将会把你传送到地狱,并使得坐标不会变化。假设你原本在主世界是(1,1,1),使用这条指令你只会跑到下界的(1,1,1),x和z轴并不会除以8。 为何?让我们来使用『流水线思维』分析一下: at first——你自己、(1,1,1)、主世界、你自己的旋转角度、feet in——你自己、(0.125,1.0,125)、地狱、你自己的旋转角度、feet \\\\in修改了维度位置到地狱,并且由于是从主世界到地狱,x和z轴就被分别除以8\\\\ positioned——你自己、(1,1,1)、地狱、你自己的旋转角度、feet \\\\positioned将坐标重新改成了你自己的坐标\\\\ 所以,你才会传送到地狱的(1,1,1)处,而不是(0.125,1,0.125)。 再来看看第二条: \/execute as @e[limit=13,sort=nearest] at @s rotated 360 -45 anchored eyes facing entity @e[limit=1,sort=nearest,distance=0.1..] feet align yzx in minecraft:the_end positioned 1 24 1.0 if predicate snow_king:0.3 run tp @s ^^^ 这条execute用到了10个子命令:as、at、rotated、anchored、facing、align、in、positioned、if和run,其中if子命令是我们接下来的内容,但早点接触也没事。 看起来很复杂的样子,但我们只需要使用『流水线思维』,拆开来逐个分析即可。 假设我们使用一个位于主世界(1,25,1)处的命令方块运行此指令(聊天框装不下这么长的指令): at first →无、(1,25,1)、主世界、(0°,0°)、feet as @e[limit=13,sort=nearest] →距离命令方块最近的实体、(1,25,1)、主世界、(0°,0°)、feet →距离命令方块第二近的实体、(1,25,1)、主世界、(0°,0°)、feet →距离命令方块第三近的实体、(1,25,1)、主世界、(0°,0°)、feet ...... →距离命令方块第13近的实体、(1,25,1)、主世界、(0°,0°)、feet at @s →距离命令方块最近的实体、距离命令方块最近的实体的位置、主世界、距离命令方块最近的实体的旋转角度、feet ...... rotated 360 -45 →距离命令方块最近的实体、距离命令方块最近的实体的位置、主世界、(0°,-45°)、feet ...... 注:大多数情况下,当水平旋转角度为360°的倍数时,游戏会将其转化为0°。 anchored eyes →距离命令方块最近的实体、距离命令方块最近的实体的位置、主世界、(0°,-45°)、eyes ...... facing entity @e[limit=1,sort=nearest,distance=0.1..] feet →距离命令方块最近的实体、距离命令方块最近的实体的位置、主世界、距离命令方块最近的实体用眼睛看向距离它最近实体的脚的朝向、eyes ...... align yzx →距离命令方块最近的实体、距离命令方块最近的实体的xyz轴向下取整的值(整数会保留)、主世界、距离命令方块最近的实体用眼睛看向距离它最近实体的脚的朝向、eyes ...... in minecraft:the_end →距离命令方块最近的实体、距离命令方块最近的实体的xyz轴向下取整的值(整数会保留)、末地、距离命令方块最近的实体用眼睛看向距离它最近实体的脚的朝向、eyes ...... positioned 1 24 1.0 →距离命令方块最近的实体、(1.5,24.0,1.0)、末地、距离命令方块最近的实体用眼睛看向距离它最近实体的脚的朝向、eyes ...... if predicate snow_king:0.3 解释如下:如果谓词条件『snow_king:0.3』通过,即运行指令 其中,谓词条件『snow_king:0.3』是数据包雪王(snow king)中的一个谓词条件(没错,就是那个『蜜雪冰城甜蜜蜜』的那个数据包),这个条件会随机一个0到1的浮点数(类似于小数),如果随机的数小于0.3就算条件通过,即运行这条指令有30%的概率。 什么是谓词条件呢?在我们讲数据包之前(也有可能永远不会讲到),你可以将这东西当作是一个打包好的『判断函数』,在这个『判断函数』里面写了一些东西,可以判断当前游戏的情况是否符合指定的条件,如果符合则通过判断,如果不符合则不通过判断。比如里面写了一个『当前游戏正在下雨』的条件,当这个条件被调用时就会看看现在游戏是否在下雨,如果下雨就会通过判断,你的指令也就能够运行,反之就不会运行。 当然,你只需要在目标选择器或execute指令中通过这个谓词的命名空间id来调用即可使用这个谓词了。只不过可惜的是,原版并没有任何的谓词条件,这谓词是专门给数据包用的东西。 run tp @s ^^^ 最多运行13次指令,分别以距离命令方块最近的实体、距离命令方块第二近的实体、第三近的实体......为执行者,(1.5,24.0,1.0)为执行坐标,末地为执行维度,执行者用眼睛看向距离它最近实体的脚的朝向作为执行朝向,eyes作为朝向基准部位。将执行者传送至(1.5,24.0,1.0),并将其旋转角度更改为执行朝向的旋转角度。 这样分析下来,是不是就清楚了许多?所以说不要慌张,这种东西仅仅只是纸老虎而已。 如果你已经是一个对nbt和方块状态较为了解的人,或许你还可以看看第三条: (实际上这有两条指令) \/execute as @e[type=arrow,nbt={inground:1b},tag=!used] at @s align xyz run summon falling_block ~~6 ~{time:1,blockstate:{name:“redstone_block“},passengers:[{id:“falling_block“,time:1,blockstate:{name:“activator_rail“},passengers:[{id:“mand_block_minecart“,mand:“\/setblock ~~1 ~ mand_block[facing=east]{mand:\\“\/execute positioned ~~-2 ~ at @e[type=item,distance=..5] run setblock ~~-1 ~ diamond_block\\“,auto:1}“,passengers:[{id:“mand_block_minecart“,mand:“\/setblock ~1 ~1 ~ chain_mand_block[facing=east]{mand:\\“\/execute positioned ~-1 ~-2 ~ as @e[type=item,distance=..5] run kill @s\\“,auto:1}“,passengers:[{id:“mand_block_minecart“,mand:“\/setblock ~2 ~1 ~ chain_mand_block[facing=east]{mand:\\“\/execute positioned ~-2 ~-2 ~ as @e[type=arrow,distance=..5] run kill @s\\“,auto:1}“,passengers:[{id:“mand_block_minecart“,mand:“\/setblock ~3 ~1 ~ chain_mand_block[facing=east]{mand:\\“\/execute positioned ~-3 ~-1 ~ run kill @e[type=mand_block_minecart,distance=..2]\\“,auto:1}“,passengers:[{id:“mand_block_minecart“,mand:“\/setblock ~4 ~1 ~ chain_mand_block[facing=east]{mand:\\“\/fill ~-4 ~~~-4 ~-2 ~ minecraft:air\\“,auto:1}“,passengers:[{id:“mand_block_minecart“,mand:“\/setblock ~5 ~1 ~ chain_mand_block[facing=east]{mand:\\“\/fill ~~~~-5 ~~ minecraft:air\\“,auto:1}“}]}]}]}]}]}]}]} \/tag @e[type=arrow,nbt={inground:1b},tag=!used] add used 这是一个作者自己写的十分典型的ooc指令,关于什么是ooc我们已经在第六十二章讲命令方块矿车时遇到过了,即『仅有一条指令』。虽然我们在那一章已经讲过了ooc的原理,但这是我们第一次在本书中遇到真正的ooc指令。很长是不是?但其实它是由多个指令,通过实体nbt的形式套娃而成的,其中用到了大量的execute指令。 如果你对此感兴趣,可以尝试拆分一下这一大串指令,猜一猜这是干什么的。我们会在之后具体讲到ooc时讲解这一大串指令。 那么本章就到此结束了。 第七十一章 条件子命令 (于2022\/7\/15重写) 还记得那些被execute替代的指令吗?其中,\/testfor、\/testforblock、\/testforblocks和\/scoreboard yers test的功能被合并到了条件子命令中,也就是if和unless子命令。 if和unless这两个子命令虽说是子命令,但它们毕竟是多条指令融合而成的,自然而然也就有『子命令』的『子命令』,所以说我们是否可以把子命令的子命令称之为execute的『孙子命令』呢? (滑稽) 虽然if和unless这两个子命令有完全相同的格式,但它们俩的效果是完全相反的: if——如果给出的条件为真(true),也就是条件成立,即通过检测,运行指令 unless——如果给出的条件为假(false),也就是条件不成立,即通过检测,运行指令 如果你看不懂上面的描述,没关系,待会我们会举些例子,毕竟上面的描述比较偏向于编程思维。 条件子命令的子命令,截止minecraft java1.19版本,一共有六个: block ——探测指定位置是否为某种方块 blocks ——将指定区域与另外一个指定区域进行对比 entity ——探测指定实体是否存在。 score ——探测指定玩家在指定计分项上的分数是否与另一个玩家在指定计分项上的分数符合指定的关系 data ——探测指定方块、实体和存储nbt是否拥有指定的nbt标签 predicate ——检查指定谓词是否通过 其中,data子命令我们放到以后讲nbt时再来(这玩意儿作为一个孙子命令,竟然还有三个子命令,也就是说execute有曾孙子了),predicate子命令我们在上一章已经遇到过了,所以我们这边就先来看看这剩下的四个子命令: block、blocks、entity和score 其中,前三者实际上根本就不用讲。为何呢?让我们看一下它们的用法: ... if|unless block <方块位置><方块id或标签>... ... if|unless blocks <源区域起始坐标><源区域终止坐标><比较区域下西北角坐标><对比模式:masked|all>... ... if|unless entity <检测目标:目标选择器>... 是不是有些熟悉?这难不成就是: java1.13之前 \/testfor <指定目标:目标选择器>[探测nbt是否符合] \/testforblock <探测位置:坐标><方块id:字符串>[数据值:整数] \/testforblock <探测位置:坐标><方块id:字符串>[方块状态] \/testforblocks <源区域起始坐标><源区域终止坐标><比较区域下西北角坐标>[<模式:masked|all>] mojang这是直接移植过来的啊,模式名都不带改一下的。 既然这些子命令和被删除的那些指令用法几乎完全一样,我们这边也就不多讲了,直接上例子。 例子一: \/execute as @e[type=yer] at @s if entity @e[distance=..1,nbt={item:{id:“minecraft:snowball“,tag:{disy:{name:''{“text“:“回城雪球“}''}}}},type=item,limit=1,sort=nearest] run tag @s add hub 这条execute有四个子命令:as、at、if和run,其效果是: 将所有在线且活着的玩家分别作为执行者,他们的位置作为执行位置,他们的旋转角度作为执行朝向,如果执行者周围1米有一个叫做『回城雪球』的雪球掉落物,就给执行者自己添加上标签hub。 其中,我们重点看一下if子命令这一段: if entity @e[distance=..1,nbt=物品是叫做『回城雪球』的雪球,type=item,limit=1,sort=nearest] 这个if子命令用到了entity,也就是相当于1.13之前的testfor指令,用于探测指定实体是否存在。在这边,entity的参数就不讲了,涉及到nbt,你大概知道是探测一个叫做『回城雪球』的掉落物就行。 让我们试一试将上面这一段if子命令转化为testfor指令: \/testfor @e[r=1,name=回城雪球,type=item,c=1] 是不是立马就理解了?所以,在使用if子命令的block、entity和blocks子命令时,不妨可以回忆回忆以前的指令是怎么个用法。 例子二: \/testforblocks ~-1 ~-1 ~-1 ~1 ~-1 ~1 ~-1 ~2 ~-1 这是我们在第三十七章讲\/testforblocks时引用的例子,其作用是『检测执行者脚下3x3的区域是否和头顶3x3的区域完全一样』,现在我们尝试将这一串指令转化为1.13+的版本: \/execute if blocks ~-1 ~-1 ~-1 ~1 ~-1 ~1 ~-1 ~2 ~-1 all 这个1.13+版本的指令和上面的testforblocks例子的效果是完全一样的,唯一需要注意的是比较模式参数从可选变成了必选,并且由于testforblocks默认就是all比较模式,所以转化后要在最后加上个『all』。 你可能会疑惑:run呢?run子命令呢?我那么大一个run呢? 其实,当一个execute指令中含有条件子命令时,就不一定要含有run子命令了。因为条件子命令也可以看做是一个具有功能的,能够返回东西的指令(毕竟原来就是由几条单独指令结合在一起的嘛)。 例子三: \/execute as @a at @s if block ~~-1 ~ redstone_block run camerashake add @s 这条指令并不适用于java版,而是适用于基岩版。 没错,这个例子是使用目前基岩版还在测试中的新版execute指令写成的,不难发现基岩版的新版execute和java版的几乎没差别。 这条指令的作用是: 将所有玩家分别作为执行者,将执行者的位置作为执行位置,将执行者的旋转角度作为执行朝向,如果执行位置下方一格方块(玩家脚底下的方块)是红石块,就摇晃玩家的镜头(站久就变鬼畜了)。 其中,指令camerashake是基岩版目前较为冷门的一个指令,因为是新添加的所以还有许多人不太了解。其实基岩版在1.16版本时添加了许多有用的指令,以后可能会专门抽出来几章讲一讲。 既然说到了基岩版的新版execute,那就不妨来看看基岩版的条件子命令格式和java版有何不同: ... if|unless block <坐标><方块id>[方块数据值|方块状态]... 看看,基岩版做得多么人性化,不一定要填写的参数就不一定要填写,一定要填写的参数就一定要填写,在这一方面java版的if blocks就做得不好,为什么一定要填写『比较模式』呢? 现在,block、blocks和entity三条子命令我们都会用了,接下来我们来看看score: ... if|unless score <比较模式>... ... if|unless score matches <范围>... 虽然score是用来替代scoreboard yers test的,但这个格式第一眼给人的感觉却像是另外一个东西:scoreboard yers operation 但这两个东西有很大的区别——前者(score)仅仅是对比分数,并不会修改两个分数;后者(scoreboard yers operation)虽然也可以对比,但更多的作用是修改分数。 而且,score可比scoreboard yers operation要简单多了,因为你并不需要考虑a新a旧,以及有多个比较目标的情况,其中的目标选择器都只能选取一个目标(看来mojang还是很人性化的对不对?)。 让我们来仔细看看上面的格式,可以发现相比scoreboard yers test,新的score不仅仅可以用来测试单个分数,还可以比较两个分数。 其中,前面部分的『a目标』『a计分项』两个参数,以及后面的『b目标』『b计分项』两个参数,就不需要我多说了吧?前者是用于指定『式子』的左侧分数x,后者是用于指定『式子』的右侧分数y。 中间部分的『比较模式』参数,也就是填写在数学上大名鼎鼎的五个符号: >——如果分数x大于分数y,则为真 >=——如果分数x大于等于分数y,则为真 =——如果分数x等于分数y,则为真 <=——如果分数x小于等于分数y,则为真 <——如果分数x小于分数y,则为真 举个例子: \/scoreboard objectives add death deathcount “死亡榜“ \/scoreboard objectives add duibi dummy “分数对比专用“ \/scoreboard yers set many_dead_times duibi 50 \/execute as @a if score @s death >= many_dead_times duibi run tellraw @s [{“text“:“兄弟,你已经死了“},{“score“:{“name“:“@s“,“objective“:“death“},“color“:“red“},{“text“:“次了!“,“color“:“reset“}] 前面的三条指令就不多讲了,你应该知道是干什么的。最后一条execute指令,将会让所有玩家分别作为执行者,如果其死亡次数(death计分项中的分数)大于等于50(也就是many_dead_times这个假玩家在duibi计分项中的值),玩家自己就会收到一条消息: 兄弟,你已经死了x次了! 其中,x指的是这名玩家在计分板death上的分数,也就是他死亡的次数。 除去这个tellraw内的json文本有一部分我们没学过以外,其他部分还是很容易理解的。 至于matches模式的比较就更简单了,这就是原本yers test子命令的功能。其中的『范围』也就是采用和目标选择器一样的『两点法』。举个例子: \/execute as @a if score @s death matches 50.. run 同上 这是上面例子的简化版,功能还是一样的。 值得注意的是,在基岩版中,『两点法』可以使用!来反选。比如: \/execute if score @s death matches !10..15 这将会测试执行者自己在death计分板上的分数,如果分数不在10~15(含)的范围内就会测试通过。同样的,基岩版在其他能用到这种『两点法』的地方基本上也能够用『!』来反选,比如目标选择器。 最后,我们来看看前一章节就已经碰到过的predicate子命令: ... if|unless predicate <谓词条件id>... 什么是谓词?我在上一章已经解释过了: 『在我们讲数据包之前(也有可能永远不会讲到),你可以将这东西当作是一个打包好的『判断函数』,在这个『判断函数』里面写了一些东西,可以判断当前游戏的情况是否符合指定的条件,如果符合则通过判断,如果不符合则不通过判断。比如里面写了一个『当前游戏正在下雨』的条件,当这个条件被调用时就会看看现在游戏是否在下雨,如果下雨就会通过判断,你的指令也就能够运行,反之就不会运行。』 举个简单的例子,假设有一位大佬做了一个数据包,其命名空间为『the_dark_forest』,里面有一个叫做『israining.json』的谓词条件。这个条件会判断当前世界是否在下雨,如果下的是普通的雨,就随机50%的几率使条件成立,如果下的是暴雨,这个几率会提升到80%。 我们可以通过如下命令来调用这个谓词条件: \/execute ... if predicate the_dark_forest:israining ... 如果你调用这个谓词条件时,游戏里正在下普通的雨,那么你的指令就有50%的几率能够运行。如果下的是雷暴雨,那么就有80%的几率会运行。如果是晴天,那么不可能会运行。 当然,你也可以将if改为unless来反转条件: \/execute ... unless predicate the_dark_forest:israining ... 这条指令和上面指令的运行条件完全是反着来的:如果是晴天,那么必定会运行;如果是普通的雨天,有50%的几率会运行;如果是雷暴雨,只剩下20%的几率会运行。 现在你懂了吧?让我们来做几道题目,巩固一下知识。 第一题:请写出下列execute指令成功运行的条件 1\/execute as @e[type=item] at @s if block ~~-1 ~ minecraft:grass_block run kill @s 2\/execute positioned 1.0 1.0 1.0 if block ~~~ minecraft:air if entity @e[distance=..2,limit=1,sort=nearest] 3\/execute unless blocks ~1 ~1 ~1 ~-1 ~1 ~-1 0 0 0 all 第二题:请写出下列execute指令最大的成功运行次数 1\/execute as @e[limit=10] rotated as @a[limit=10] run tp 1 1 1 2\/execute if predicate the_dark_forest:israining 3\/execute if score @e = score @e run say hello! 所以这就是我们本章的全部内容,下一章我们将会来初步了解一下存储子命令。 ...... ...... ...... ...... ...... ...... 参考答案 第一题: 1所有维度的已加载区块内必须要有掉落物类型的实体,且至少有一个掉落物的下方方块是草方块 2坐标(1.0,1.0,1.0)处的方块必须是一个空气方块,且范围2米内必须要有一个实体存在。 3执行地点上方3x3的范围与范围(0,0,0)-(3,0,3)完全一致,且执行地点上方3x3的范围没有超出世界边界 第二题: 1100(as的参数指定了10个实体,rotated的参数也指定了10个实体) 21(跟if子命令没关系) 30(在java版中,score子命令的两个目标选择器参数都不能指定多个实体)或1(在基岩版中,只要@e实际只选择到了1个实体就行) 第七十二章 存储子命令 (本章已于2022年7月16日重写) 现在,我们只剩下了一个存储子命令,即store。 这个store可不是商店,而是一个动词,意为『储存』。 和if子命令一样,store子命令也有许多子命令。截止1.19版本,store子命令一共有5个子命令,但在这我们只能讲一个。 为什么?你仔细看看这五个子命令,斟酌一下你的水平,然后你就会发现在这里我们的确也只能讲一个。 这五个子命令分别是: block ——将值存储到方块实体(方块nbt)中 bossbar ——将值存储到boss栏中 entity ——将值存储到实体nbt中 score ——将值存储到计分板中 storage ——将值存储到硬盘中 额,其实storage子命令我们也可以稍微讲一下...... 在开讲之前,让我们先回顾一下第六十一章的内容。在那一章,我们了解到指令的返回结果有五种类型: 1指令执行成功的次数(sesscount) 2指令的查询结果(queryresult) 3受到该指令影响的物品数量(affecteditems) 4受到该指令影响的实体数量(affectedentities) 5受到该指令影响的方块数量(affectedblocks) 但mojang可能觉得这五种太多了,而且2、3、4、5分得那么细也没啥用。于是,在java1.13版本中,后四类合并成了一类,加上原先『指令执行成功的次数』,就变成了两大类型: 1指令执行成功的次数(sess) 2指令返回的结果(result) 其中,前者可以被我们的比较器探测到并输出为红石信号强度。 回到store子命令上。虽然现在指令执行的结果只剩下两大类型,但也是有分类的嘛。所以说,store子命令的格式如下: ... store <返回类型>(block|bossbar|entity|score|storage)... 比如: ... store result block ... 这将会指定将指令执行所返回的结果(一般是run子命令执行的结果)存储到方块实体(方块nbt)中。 考虑到我们尚未真正开始学习nbt,因此这里我们就不讲block、bossbar和entity了,就仔细学习一下score,并稍微讲一下storage即可。 store的score子命令,其格式如下: ... store <返回类型> score <分数持有者><计分项>... 很简单吧?至少比\/stats指令要简单许多。我们只需要指定返回类型,然后指定要存储到谁在哪个计分项上的分数即可。我们不需要考虑会不会受到其他指令的影响,也不需要考虑要在开始存储之后停止存储,甚至不需要考虑指定的分数持有者是否在被指定的计分项追踪。 举个简单的例子: \/execute as @a store result score @s ore_count run clear @s #forge:ores 0 在装了forge模组加载器的情况下,运行上述指令将会将所有玩家背包内的矿石数量储存到每名玩家的ore_count计分项上。假设在线玩家张三(id:zhang_san)背包内有25个铁矿石、17个深层铁矿石、45个工业时代2的锡矿石,那么运行上述指令后,张三在ore_count计分项上的分数会更改为87(25+17+45)。 这是store子命令比较常见的用法。 但在上一章讲条件子命令时,我曾经说过这么一句话: 『因为条件子命令也可以看做是一个具有功能的,能够返回东西的指令(毕竟原来就是由几条单独指令结合在一起的嘛)。』 所以,store子命令是否可以存储条件子命令所返回的结果呢? 答案是可以的。比如下面这一条: \/execute store result score slime_count counter if entity @e[type=minecraft:slime] 这将会统计出当前所有已加载维度的已加载区块的史莱姆数量,并将其以分数的形式储存到虚假玩家slime_count于计分项counter上的值。 需要注意的是,你不能这么写: \/execute if entity @e[type=minecraft:slime] store result score slime_count counter 虽然这么写也能执行指令,但是将会没有任何效果。 下面我们再来看两个例子: 1\/execute store result score item_count counter if entity @e[type=minecraft:item] store result score cow_count counter if entity @e[type=cow] 2\/execute store result score item_count susu if entity @e[type=minecraft:item] store result score cow_count susu if entity @e[type=cow] store result score yer_count susu run execute if entity @e[type=yer] 第一个例子中有两组store+if。第二个例子中,在第一个例子的基础上,又加上了第三个store和一个run子命令来运行『execute if entity @e[type=yer]』。 我们先来看看第一个例子。假设现在有2个掉落物,3头牛,请你猜一猜,运行这条指令会发生什么? a.出现错误。 b.item_count的分数变成2,cow_count的分数变为3。 c.item_count的分数变为3,cow_count的分数变为3。 d.item_count的分数变成2,cow_count的分数变为2。 请你将公屏,打在你的答案上。 (这哪有公屏,这只有评论啊) 让我们等五秒钟,看看答案是什么。 五 四 三 二 一 答案是: c! 当一个不带有run子命令的execute指令中含有多个store和条件子命令时,除了在最后一个条件子命令后面的store子命令收不到数据以外,其他的store子命令将会获取到最后一个条件子命令的数据。 但需要注意,虽然store子命令只能获取到最后一个条件子命令的数据,但是这不代表其他条件子命令没有作用。如果前面的条件子命令发现条件不符合的话,那么store就会无法获取到任何数据而不更改分数。 我们再来看看第二个例子。假设现在还是有2个掉落物,3头牛,1个玩家,请你猜一猜,运行第二个例子会发生什么? 答案是:item_count、cow_count和yer_count的分数均会变为1 当一个带有run子命令的execute指令中含有多个store和条件子命令时,store子命令仅仅只会获取到run子命令运行的数据,并不会获取到其他条件子命令的数据。 你听懂了吗? 在本章的最后,我们来稍微了解一下store的这个storage子命令。 storage子命令(store)和predicate子命令(if|unless)都是在java1.15版本中被添加的,并不是java1.13一开始就有的。有趣的是,这两个东西都和数据包有较大关系。谓词我们已经知道了,那这个storage子命令又是什么呢? 正如我对这条子命令的描述一样,这条子命令可以将返回的值存储到硬盘上。更确切地说,是存储到指定的存储容器中(这是minecraft wiki的说法)。 硬盘?存储容器?都是什么鬼! 待会你就知道是什么鬼了。让我们先来看看这东西的格式: ... store <返回类型> storage <目标存储容器id><数据类型><倍率>... 举个简单的例子: \/execute store result storage minecraft:distance to_the_nearest_vige double 1.0 run locate structure #minecraft:vige 这条指令适用于java1.19及以上版本,效果是:将执行地点与最近村庄的距离以double双精度浮点数类型存储到名为『minecraft:distance』容器内的to_the_nearest_vige标签。 如果你的存档是个全新的,那么你在运行上述指令后,首先游戏将会给你创建一个叫做『minecraft:distance』的存储容器,这个存储容器以nbt树状结构存储数据,并放置于你的存档目录下的data文件夹内的mand_storage_minecraft.dat文件中,具体路径如下: 存档根目录\/data\/mand_storage_minecraft.dat.data.contents.distance 其中,前面的『存档根目录\/data\/mand_storage_minecraft.dat』是文件路径,后面的『data.contents.distance』是nbt路径。 如果你看不懂也没关系,你只需要了解一件事情:计分板数据也是差不多这样子存储的——计分板存储在data文件夹下面的另外一个叫做scoreboard.dat的文件中。 然后,游戏会在这个叫做『minecraft:distance』的存储容器内部,在nbt根目录创建一个to_the_nearest_vige标签,并以double的形式写上取得的数据。 这样子,你通过execute指令获得的数据就存储在了硬盘上,而且你可以随时调用。 怎么个调用法?使用\/data指令获取: \/data get storage minecraft:distance 如果先前你运行指令时,执行地点与最近村庄的距离世362格,那么这将会返回: 存储minecraft:distance含有以下内容:{to_the_nearest_vige:362.0d} 虽然使用起来十分容易,但由于涉及到较多的nbt知识,以及我们尚未讲过的\/data指令(这玩意可比execute更加复杂),所以这边就不细讲了。 你只需要知道四点: 1这玩意可方便了 2容器名称只要符合规范,随便写(如hentai:photos、i_am_a_shuabi:things) 3标签名称只要符合规范,也随便写(如a_photo、what_up) 4数据类型一般用int即可 那么本章就到此结束了。 第七十三章 基岩版的新版execute (本章于2022年7月17日重写) 2022年7月12日,基岩版1.19.10版本正式发布。这次更新中,对指令方面有三个重要的改变: 1\/locate指令正式变得更高级了 2\/execute指令开始尝试(实验)变得更高级了 3开始实验旁观模式了 这三个改变,随便一个拿出来,都是能够让基岩版玩家开心一整天的。但mojang真的是太良心了,竟然一下子就给出了三个大改变,这不得让基岩版玩家开心个整整三天? 其中,\/locate指令的变化我们在第六十七章已经讲过了,我们这一章主要来看看基岩版新版的\/execute指令。 \/execute 基岩版1.19.10之后的格式: -修饰子命令 ... as <执行者:目标选择器>... ... at <实体:目标选择器>... ... positioned <坐标>... ... positioned as <实体>... -条件子命令 ...(if|unless) block <方块位置><方块id>[方块数据值|方块状态]... ...(if|unless) blocks <源区域起始坐标><源区域终止坐标><比较区域下西北角坐标><对比模式:masked|all>... ...(if|unless) entity <检测目标:目标选择器>... ...(if|unless) score <比较模式>... ...(if|unless) score matches <范围>... -运行子命令 ... run <指令>... 看看,是不是和我们前几章学的java版格式,十分的像? 其实除了条件子命令的block子命令外多出了一个可选的『方块状态|方块数据值』参数外,其他的格式都和java版一模一样,只不过少了存储子命令、一大堆修饰子命令和一小部分条件子命令的子命令而已。 所以说这些子命令的功能以及使用方法我们就不需要也不必要讲了,因为我们之前都已经讲过了。 那么本章就到这里。如果基岩版的execute有新的变化,我将会尽早更新这一个章节。 第七十四章 探究:execute的运行流程 (注:非常不推荐在手机上阅读此章节,请使用平板或电脑阅读此章) (本章用到了大量的字符画,有可能会出现严重的错位情况,可手动调整字体和大小至最佳状态) (此章节已于2022年7月17日重写) 在第六十九章,我为了提醒你注意各个子命令的顺序,专门举了个例子: \/execute as @e at @e run tp @s ~~1 ~ 但是你是否有注意到游戏运行这条指令的过程: 1将玩家传送至玩家上方1米的位置(玩家此时抬高了1米) 2将玩家传送至村民上方1米的位置(玩家此时位于村民上方1米) 3将玩家传送至羊上方1米的位置(玩家此时位于羊上方1米) 4将村民传送至玩家上方1米的位置(村民此时位于玩家原本位置上方1米,玩家此时位于羊上方1米) 5将村民传送至村民上方1米的位置(村民此时位于村民原本位置上方1米,玩家此时位于羊上方1米) 6将村民传送至羊上方1米的位置(村民和玩家此时位于羊上方1米) 7将羊传送至玩家上方1米的位置(村民和玩家此时位于羊原本位置上方1米,羊位于玩家原本位置上方1米) 8将羊传送至村民上方1米的位置(村民和玩家此时位于羊原本位置上方1米,羊位于村民原本位置上方1米) 9将羊传送至羊上方1米的位置(村民、玩家和羊此时都位于羊原本位置上方1米) 这个过程有何特殊的呢? 你仔细看看第4、5、7、8和9条过程,你有没有什么发现? 当游戏将村民传送至玩家上方1米的位置时,虽然玩家已经被传送至了羊上方1米的位置,但游戏仍然将村民传送至玩家原本位置上方1米,而不是羊上方2米的位置。 这是怎么回事? 我们设玩家(2,2,2)为a、村民(3,2,3)为b、羊(4,2,4)为c,游戏在运行execute时,其实它的流程是这样的: execute---a---------b---------c 游戏先解析as @e,得到了上面的三个目标。 execute---a---------b---------c ------------↓---------↓----------↓ ---------2·2·2-----2·2·2-----2·2·2 ------------↓---------↓----------↓ ---------3·2·3-----3·2·3-----3·2·3 ------------↓---------↓----------↓ ---------4·2·4-----4·2·4-----4·2·4 然后游戏会解析at @e,预先将实体的位置记录下来。上面为了方便展示,用x·y·z来表示坐标。 execute---a------------------------b-----------------------c ------------↓-------------------|----↓------------------|-----↓ ---------2·2·2—3·2·3—4·2·4-|-2·2·2—3·2·3—4·2·4-|-2·2·2—3·2·3—4·2·4 ------------↓-------↓-------↓---|----↓------↓-------↓---|----↓-------↓-------↓ -----------1------2------3---|---4-----5------6---|---7------8------9 1:\/tp 玩家名 2 3 2 2:\/tp 玩家名 3 3 3 3:\/tp 玩家名 4 3 4 4:\/tp 村民uuid 2 3 2 5:\/tp 村民uuid 3 3 3 6:\/tp 村民uuid 4 3 4 7:\/tp 羊uuid 2 3 2 8:\/tp 羊uuid 3 3 3 9:\/tp 羊uuid 4 3 4 接下来游戏会解析run tp @s ~~1 ~,根据三要素,将其中的目标选择器和相对坐标等参数具体化(但计分板分数之类的不会具体化,因为没必要),得到具体的指令(如上)。 最后,游戏运行具体的指令,也就是本章最开头的那九个过程。 其中,最重要的,也是最关键的一点,就在于execute指令解析at @e的过程。 execute并不是说运行一次解析一次,而是先全部解析了再运行,所以并不会使得『村民传到玩家传送过后上方1米的位置』之类的事情发生。 能理解吧? 那问题来了,如果execute再套一个execute会发生什么?比如我们将上述指令写成: \/execute as @e run execute at @e run tp @s ~~1 ~ 其实效果还是一样的,具体原因就等你自己去推导吧,按照我上面的流程去推导。 这就是java execute 1.13+版本的运行流程。如果你还不懂,我们再看一个简单并且效果比较明显的例子。 设有盔甲架a和b,分别位于主世界的(40,-60,29)和(42,-60,29)。盔甲架a的生成时间比盔甲架b更早,已加载区块中没有其他盔甲架。在盔甲架a、b旁运行如下指令: \/execute as @e[type=minecraft:armor_stand] at @s run tp @e[type=minecraft:armor_stand,distance=1..3]~~10 ~ 让我们分析一下,运行上述指令会发生什么。 首先,如果我们按照正常的思维去分析这条指令,就会得到以下结果: a会先将b传送到自己上方10米的位置,b由于处于那个位置无法选取到a来传送,最终仅仅b会被传送到a的上方10米处。 但其实,如果你真的去运行这条指令,就会发现a和b都会被传送到对方原位置的上方10米处。 为什么?我们按照游戏的思维分析一下就可以了: execute---a---------b 游戏先解析as @e[type=minecraft:armor_stand],得到了上面的两个目标:盔甲架a和盔甲架b。 execute---a--------------b ------------↓--------------↓ -------40·-60·29-----42·-60·29 然后游戏会解析at @s,预先将实体的位置记录下来。 execute---a--------------b ------------↓--------------↓ -------40·-60·29-----42·-60·29 ------------↓--------------↓ -----------1-------------2 1:\/tp 盔甲架b的uuid 40 -50 29 2:\/tp 盔甲架a的uuid 42 -50 29 接下来游戏会解析run tp @e[type=minecraft:armor_stand,distance=1..3]~~10 ~,根据三要素,具体化指令,得到具体的指令。由于此时还未传送,所以目标选择器会分别选择到『盔甲架a』和『盔甲架b』。 最后,游戏按照顺序执行指令,分别将盔甲架a和盔甲架b传送到对方上面10米高的位置。 这个例子比较简单,你应该能够理解吧? 所以你明白了吗? 上面讲的是java1.13更新后的execute指令其运行的具体流程,那么java1.13更新前的呢?以及基岩版的呢? 2016年6月22日,mcbbs大佬pca006132在『矿工茶馆』发布了一个猜猜乐(id:),大致的问题如下: execute @e ~~~... summon armorstand,这个指令在初始实体不同数目的时候出来的结果是什么 没想到竟然没人能够解答这个问题,于是这位大佬在次日讲解了这个问题(帖子id:)。他举了一个简单的例子: 当初始实体数为2时,运行execute @e ~~~ execute @e ~~~ summon armorstand 这个例子的结果竟然是8。 那如果在相同的初始情况下,运行execute @e ~~~ execute @e ~~~ execute @e ~~~ summon armorstand,即套了三个execute的指令会发生什么? 答案是:2048。 很令人震惊啊!那为什么会这样呢? 如果我们在java1.13及以上版本,运行类似的指令,将达不到一样的效果,因为在java1.13之前,execute的运行逻辑是完全不一样的。 那么到底是个怎么个逻辑法呢?其实在java1.13前,execute并不会在运行前先存好各种数据,而是运行一遍解析一遍。以上面那个嵌套了3层execute的指令为例子,我们来解析一下。 条件:初始两个实体a(1,2,1)和b(2,2,2),a比b离执行地点更近。 execute---a----------b ------------↓ ----------1·2·1 游戏先解析第一个『execute @e ~~~』,得到了上面的结果。后面我们将会忽略执行地点,因为这边不需要考虑执行地点的影响。 execute---a----------b ------------↓ ---------a——b 游戏按照顺序,先以a为执行者运行指令,并解析了第二个『execute @e ~~~』,得到了上面的结果。 execute---a----------b ------------↓ ---------a——b ---------↓ ------a——b 游戏按照顺序,再次以a为执行者运行指令,并解析了第三个『execute @e ~~~』,得到了上面的结果。 execute---a----------b ------------↓ ---------a——b ---------↓ ------a——b ------↓-----↓ ------c-----d 第三个execute运行指令,产生了新的盔甲架c和d。 execute------a----------b ---------------↓ ---------a————b ---------↓---------↓ --------+2---b—a—c—d 游戏回到第二层execute,以目标选择器顺序选取b为执行者,由于之前已经生成了c和d,所以b运行第三层execute指令时,会选取到4个实体来运行指令,最终实体数量+4(现在为8=2+2+4)。 execute---a-----------------b ------------↓-----------------↓ ----------+6----b—a—c—d—e—f—g—h 游戏回到第一层execute,以目标选择器顺序选取b为执行者。由于已经有了八个实体,因此这一次第二层execute会选取到八个实体来运行第三层execute。 execute---a-------------------------b ------------↓-------------------------↓ ----------+6----b——a——c——d———e———f———g———h -----------------↓-----↓-----↓-----↓-------↓-------↓-------↓-------↓ --增加实体数---+8--+16--+32-+64--+128--+256---+512--+1024 --增加后数量----16---32---64---128----256---512----1024---2048 随后,游戏按照顺序依次以这八个实体运行指令,实体数量在此过程中快速增长,最终变为2048。 不难发现,每一次第三层的execute指令被运行,都会将当前实体数量x2,而上面一共运行了10次第三层的execute,相当于2被乘以了10次2,也就是2x2x2x2x2x2x2x2x2x2x2,即2的11次方,结果为2048,即2048个实体。 实在是太令人惊讶了是不是?在java1.13以下的execute指令中,execute仅仅会在被选取的执行者开始执行指令时才会进行下一步的解析动作,而且不会一下子就将所有执行者运行指令的情况全部解析出来再运行指令。 所以,java1.13对execute的改动不仅仅是格式上的,还有运行流程上的改动。 如果你并不能很好理解上面为什么会由2个实体产生出2048个实体,别担心,我们继续以刚才两个盔甲架互相传送为例子,看看类似的指令在java1.13以下的版本有何不同的效果。 还是设有盔甲架a和b,分别位于主世界的(40,60,29)和(42,60,29)。盔甲架a的比盔甲架b更靠近执行地点,已加载区块中没有其他盔甲架。在盔甲架a、b旁运行如下指令: \/execute @e[type=armor_stand]~~~ teleport @e[type=armor_stand,r=3,rm=1]~~10 ~ 游戏先解析『execute @e[type=armor_stand]~~~』得到如下结果: execute---a----------b ------------↓ -------40·60·29 然后以a为执行者,解析『teleport @e[type=armor_stand,r=3,rm=1]~~10 ~』,得到了如下指令: \/teleport 盔甲架b的uuid 40 70 29 运行上述指令,盔甲架b被传送至(40,70,29)处。随后游戏以b为执行者,先解析执行地点参数『~~~』,得到如下结果: execute---a------------------b ------------↓------------------↓ -------40·60·29---------40·70·29 --将b传送至40·70·29 接下来,游戏以b为执行者,再次解析指令,得到如下内容: 选择器''@e[type=armor_stand,r=3,rm=1]''什么都没找到 没错,由于b被传送到了(40,70,29),因此目标选择器就选不到a,自然就无法执行指令。最终,正如我们在最开始以正常思维分析的那样,得到了如下结果: a会先将b传送到自己上方10米的位置,b由于处于那个位置无法选取到a来传送,最终仅仅b会被传送到a的上方10米处。 虽然在java1.13更新后,我们的『正常思维』没用了,但在java1.13以下版本还是很准的。 那在基岩版呢? 作者在基岩版也测试过了(用的上面的两个盔甲架tp法),确认基岩版不管是旧版还是新版(1.19.10更新的)的execute,都是会得到和java版1.13以下版本一模一样的数据。 其中,对于目前还在测试的新版execute,用的是如下指令: execute as @e[type=armor_stand] at @s run tp @e[type=armor_stand,r=3,rm=1]~~10 ~ 也就是说,如果你在基岩版运行上面套了3层execute的生成指令,在初始实体数为2的情况下,也会得到有2048个实体的纟 ...... ...... ...... :( 你的电脑遇到问题,需要重新启动。 我们只收集某些错误信息,然后为你重新启动。 ...... ...... ...... ——附录:跟本章有关系的mcbbs帖子原链接 (上述帖子均已被mcbbs论坛系统自动关闭) 第七十五章 局部坐标与执行朝向 (本章于2022年7月18日重写) (建议阅读本章的读者需具备一定的空间想象能力,并预先准备好笔和草稿纸,或一个3d画图软件) 本章以及接下来两章原本是讲execute的条件子命令和存储子命令的,结果本书第一次大修中这些内容在前面几章讲完了,这几章就空出来。 所以这一章,我们就来研究一下:局部坐标与执行朝向的关系。 在第五十九章『更深入地了解坐标』中,我们了解到局部坐标是以执行者的头为原点,但其实这个观点是完全错误的。要想纠正这个错误,我们就得了解到局部坐标的本质。 局部坐标的本质是什么呢?简单来说,局部坐标就是一种基于相对坐标并受执行朝向影响的一种坐标。局部坐标的原点在相对坐标的基础上计算而成,三个坐标轴根据执行朝向不断改变其倾斜角度。 为了能够更好理解局部坐标的本质,我们可以以执行地点为圆心o,任意实数r为半径,画一个处于水平面上的圆,这个圆我们可以称之为『水平朝向圆』,用来代表水平旋转角度。然后,我们再以同样的点o为圆心,同样的r为半径,画一个和绝对y、z坐标轴处于相同平面上的圆,这个圆我们可以称之为『垂直朝向圆』,用来代表垂直旋转角度。 画出来后,我们就会发现这两个圆组成了一个球体,这个球体我们可以称之为『朝向球』。(注:这些名词都是作者自己编的) 在这个『朝向球』中,『水平旋转圆』和『垂直旋转圆』的边有两个交点,这两个交点就分别代表着(180°,0°)和(0°,0°)这两个特殊的旋转角度。由于这两个交点所代表的旋转角度很特殊,我们就将这个『朝向球』称之为『标准朝向球』,意指这个朝向球代表着标准的、默认的朝向。 在minecraft中,命令方块执行指令时,它的朝向球就是这样子的,因为本身其没有朝向,所以默认采用『水平朝向正南』的朝向来执行指令。 但是在玩家身上呢?甚至在其他实体身上呢?由于实体的朝向会不断改变且不标准,所以每个实体朝向球内的『水平朝向圆』和『垂直朝向圆』并不一定处于水平面和绝对yz坐标的平面上,而是有一个偏差的角度。 比如说这位玩家,他的水平旋转角度为76°(南偏西76°),垂直旋转角度为-27°(水平向上27°)。我们以这位玩家的位置作为圆心o,以任意实数r为半径,画出的『水平朝向圆』所在的平面和水平面的夹角为27°,画出的『垂直朝向圆』所在的平面和绝对yz坐标轴所在的平面的夹角为76°(或104°)。 不难发现,在这种不标准的朝向球中,『水平朝向圆』倾斜的角度是由『垂直旋转角度』决定的,而『垂直朝向圆』偏差的角度是由『水平旋转角度』决定的,两者是互相影响的关系。 如果你读懂了上面的内容,那么恭喜你,我们现在可以尝试加点儿料来切入主题了。如果你没有读懂,也没事,画点图,或者搜一搜和上述概念很类似的『天球』,了解了解,你大概也就懂了。 我们还是以刚才那位玩家的朝向球为基础,你会发现在这个朝向球中也有两个交点,分别代表着(76°,-27°)和(-104°,27°)的朝向,前者是玩家正面的朝向,后者是玩家背面的朝向。我们设前者为a点,后者为b点,过ab点作直线ab,这条直线ab必定会过圆心o点。 现在,我们把这条直线ab当作是一个原点是o的坐标轴,向a点方向为正方向,向b点方向为反方向。这条坐标轴是什么呢?就是这名玩家局部坐标的z坐标轴! 然后,我们隐藏掉『垂直朝向圆』,只看『水平朝向圆』和z坐标轴。我们能够看见z坐标轴和圆的边有两个交点,这两个交点也就是上面的a点和b点。 我们过圆心o作z坐标轴的垂线,分别交『水平朝向圆』的边于c、d两点。这个垂线也就是这名玩家局部坐标的x坐标轴。那么这个x坐标轴的正方向在哪里呢?你当然可以通过左正右负判断出来,但是这样子也过于浅显了一些。我们必须要找到c点和d点这两点分别的含义,才能确定x坐标轴的正方向在哪里。 由于x轴和z轴互相垂直,因此这里就形成了四个直角三角形——∠aoc、∠aod、∠boc和∠bod。由于这四个角都是圆心角,所以我们就可以得到它们对应的弧ac、ad、bc、bd的长度都是90°。 别忘了,这里的圆是『水平朝向圆』,所以这里弧长的实际意义都是水平旋转角度。在这边,我们把『水平朝向圆』所代表的旋转角度当成是相对水平旋转角度,a点为0°点,顺时针增加度数,因此我们就可以得到a、b、c、d四个点分别代表的度数: a:0° b:180° c:90°(或270°,看你是怎样标的) d:270°(或90°) 现在我们得到了这四个点所代表的『相对水平旋转角度』的度数。那问题来了,这个度数的实际意义是什么? a为0°,代表着正前方;b为180°,代表着正后方;c为90°(或270°),代表着正右方向;d为270°(或90°),代表着正左方向。而据我们所知,局部坐标x轴的正方向是向右,所以在这边,x坐标轴朝向d点(或c点)的方向为正方向。 接下来,我们来看看『垂直朝向圆』,把最后的y坐标轴也画出来。还是故技重施,过圆心o作z坐标轴的垂线,分别交『垂直朝向圆』的边于e、f两点,这个垂线也就是这名玩家的y坐标轴。仔细观察e、f点,想象一下当玩家朝向改变时,e、f点会怎么运动。你会发现e点(或f点)不管怎么运动,都不会超出『垂直朝向圆』上代表着垂直旋转角度为0°~-180°的圆弧,也就是说不会跑到过o点水平线以下的位置。所以,这个y坐标轴朝向点e(或点f)的方向为正方向,朝向点f(或点e)的方向为负方向。 如果你能够理解上面的内容,那么恭喜你,你已经很清楚局部坐标与旋转角度的关系了。 但局部坐标的原点呢? 局部坐标的原点默认是执行者的脚部坐标,也就是执行地点。但我们可以通过execute指令来改变执行朝向的基准部位到眼睛,来改变局部坐标的原点位置。那么改变之后,局部坐标的原点会有什么变化呢?让我们来看看下面几条指令: 1\/execute as @s positioned 50.0 -60 50.0 anchored eyes run tp @s ^^^ 2\/execute as @e[type=cow,limit=1] positioned 50.0 -60 50.0 anchored eyes run tp @s ^^^ 运行第一条指令,你会发现你被传送到了(50.0,-58.38,50.0),y坐标并不是-60,而是抬高了1.62米。但如果我们运行第二条指令,你会发现牛被传送到了(50.0,-58.7,50.0),仅仅抬高了1.3米。所以说,当基准部位改变时,游戏会根据当前指令的执行者来判断眼部坐标的具体位置,而不是一定就抬高一个固定的值。如果执行者不是一个实体,那就没有眼睛,将不会对执行朝向的原点以及局部坐标的原点有任何的变化。 这就是局部坐标与执行朝向的关系。需要注意的是,在tp和teleport指令中,局部坐标的旋转角度和原点是分家的——旋转角度会采用传送目标的旋转角度,而原点会基于执行地点计算出来,两者的来源并不一样。 这就是本章的全部内容了,你读懂了吗? 第七十六章 camerashake-如何让一个玩家鬼畜 在前面的两章,你可能花费了大量的脑细胞来理解里面的内容,为了保住你的脑子不会被消耗完,我们接下来就放轻松一些,来学习一些虽然冷门但有趣又简单的指令。 在第七十一章我们讲条件子命令时,曾经举了这么一个例子: \/execute as @a at @s if block ~~-1 ~ redstone_block run camerashake add @s 这条指令的作用是: 『......如果执行位置下方一格方块(玩家脚底下的方块)是红石块,就摇晃玩家的镜头(站久就变鬼畜了)。』 其中,我们用到了一个目前基岩版独有的指令:camerashake。这一章,我们就来介绍一下这个指令。 \/camerashake 作用:摇晃玩家视野 存在版本:基岩版1.16.100-今 需要权限等级:基岩版-1 需要作弊:是 格式: \/camerashake add <目标玩家>[摇晃强度][摇晃时长:秒][摇晃方式] \\\\为指定玩家的视野添加摇晃效果\\\\ \/camerashake stop [目标玩家] \\\\为指定玩家的视野移除摇晃效果\\\\ 这是一个很简单的指令,你可以为指定的玩家添加摇晃效果,也可以为你自己或指定的玩家移除摇晃效果。让我们先来简单试一试: \/camerashake add @s 使用上述指令,你会发现你的视角轻微了摇晃了1秒左右,但并不怎么强烈。 我们可以尝试添加更多的参数,比如指定多强的摇晃强度和摇晃时间: \/camerashake add @s 0.4 10.0 上述指令可以给你自己添加强度为0.4且长达10秒的坐标摇晃效果。虽然说是摇晃视角,但如果你真的运行,你会感觉并不是你在摇晃,而是整个大地都在摇晃,就像地震了一样(而且晃久了还会有些晕)。 需要注意,『摇晃强度』和『摇晃时长』这两个参数的值类型都是浮点数,也就是说你要按照小数的写法来写,就算是整数也要在后面加上个『.0』。并且,『摇晃强度』参数的值必须在0~4之间(含0和4)。 回到上面的指令,你可能会发现作者对这条指令的描述中说到『坐标摇晃效果』。这个『坐标摇晃效果』是什么呢?其实就是指以不断随机改变玩家摄像机(视野)的坐标的方式来实现摇晃的效果,这种方式指定的强度越大,随机变化坐标的跨度越大,摇晃的效果也就越强烈。当然,这并不会改变玩家本身的坐标。 我们可以通过指定『摇晃方式』参数,来改变摇晃的效果。这个参数可以填写两个值:positional(坐标摇晃[默认])和rotational(角度摇晃)。 让我们看一下角度摇晃的效果: \/camerashake add @s 0.4 10.0 rotational 不难发现,角度摇晃其实就是通过不断随机改变摄像机(视野)的旋转角度,来实现摇晃的效果。当然,这也不会改变玩家本身的旋转角度。 虽然摇晃会在时长之后结束,但如果我们指定的时长过长,就需要使用stop子命令来强制结束: \/camerashake stop 这将会结束执行者自身的视野摇晃。你也可以通过指定『目标玩家』参数,来停止特定玩家的视野摇晃。 需要注意的是,如果你不断给一名玩家添加摇晃效果,新添加的摇晃效果虽然会覆盖之前的摇晃效果,但在强度方面则会在原先的摇晃效果上增加。比如本章最开始的execute指令,如果一名玩家在红石块上站了7游戏刻,那么这名玩家的视野将会被添加七个摇晃效果,强度最终会变为0.5x7=3.5(注:作者测试默认强度大约是0.5,可能会有些误差),这名玩家的视野将会在接下来1秒内变得十分鬼畜。 这就是本章的全部内容了。 附表:camerashake历史 基岩版 1.16.100-加入了\/camerashake 1.16.210-加入了stop子命令用于停止玩家视野摇晃。 第七十七章 damage-造成伤害 村民可以攻击吗?答案当然是否定的。就算村民发射的烟花火箭爆炸会有伤害,这也不是村民本身的攻击。 在java版,如果你能精准地把握住时间,将一个弹射物(如箭)的uuid改成一个村民的uuid,确实有可能会使得村民“攻击”其他生物。那在基岩版呢? mojang虽然没有给我们操控nbt来修改uuid的方式,但却给了我们一条指令:\/damage \/damage 作用:对指定实体造成伤害 存在版本:基岩版1.18.10-今 需要权限等级:基岩版-1 需要作弊:是 格式: \/damage <目标实体><伤害大小:非负整数>[伤害类型] \/damage <目标实体><伤害大小:非负整数><伤害类型> entity <伤害来源> 你可以指定『目标实体』和『伤害大小』参数,来简单的对指定实体造成伤害。如果还指定了『伤害类型』和『伤害来源』参数,就可以确定是谁对谁造成了伤害。比如下面的指令: \/damage @s 20 entity_attack entity @s 这将会使你自己对你自己造成20点的实体攻击类型伤害,然后你就会收到这么一条消息: 你自己的游戏名被 你自己的游戏名杀死了 我杀我自己? 虽然你可以不指定伤害类型来造成伤害,但这样子就会导致你死亡时,只会显示出如下信息: xxxxxx 死了 所以我们最好指定伤害类型。那有哪些伤害类型呢?我会将截止1.19.10版本的伤害类型列表放到本章末尾。 我们还可以指定『伤害来源』,来指定到底是谁造成了伤害。比如在上面的例子中,我们就指定了伤害来源为自己,这样子就实现了『自己』对『自己』造成了伤害。 伤害来源这个参数有很多奇妙的用途,比如下面的指令: \/damage @e[type=iron_golem] 1 entity_attack entity @e[type=viger,c=1] 这将会使得距离执行地点最近的村民对所有铁傀儡造成1点的伤害,然后你就会看见...... 『妈呀!铁傀儡杀村民啦!!!』 如你所见,伤害来源不仅仅可以使得死亡信息发生改变,还可以转嫁生物仇恨,使得铁傀儡亲手杀死了村民。 但伤害来源的用途不止这么简单。假设这里有一只猪,它静止在原地。 我们运行下面的指令对它造成伤害,仔细观察猪受到攻击的情况: \/damage @e[type=pig] 1 entity_attack 猪→ 红猪→ e=e=猪(跑)→猪 你会发现,猪仅仅受到了攻击,然后开始四处乱跑而已。让我们等一下它跑完,然后运行下面的指令再次造成伤害:\/damage @e[type=pig] 1 entity_attack entity @s 猪→ e=红猪(被击退)→e=e=猪(跑)→猪 你会发现,猪不仅仅受到了攻击,还向一个方向退了几步。 通过上面的实验,你会发现:指定『伤害来源』参数还可以使得攻击有一定的方向。那么这个方向是怎么计算出来的呢? ██████████民→██ ██████████████ █████←猪███████ ██████████████ 我们来看看上述网格,箭头代表着实体的朝向。让我们尝试指定村民对猪造成伤害: \/damage @e[type=pig] 1 entity_attack entity @e[type=viger,c=1] 然后你就会发现猪被击退向了远离村民的方向: ██████████民→██ ██████████████ ██████████████ ████←猪████████ 这说明了什么?这说明了,指定『伤害来源』后,造成的攻击会具有方向,而这个方向和指定的攻击者向着被攻击者的方向是一致的。 但是需要注意,这个攻击方向的计算是2维的,并不是3维的。 什么意思呢?也就是说,攻击方向的计算不会考虑到两者的y坐标,仅仅会通过两者的xz坐标计算得出。所以你并不能通过召唤一个盔甲架,然后你站在上面,不断让盔甲架给你造成伤害使得你上天。你只会从天上被打下来。 那么这就是本章的全部内容了。 附表1:截止1.19.10版本所有伤害类型id表 id——死亡信息 anvil —— xxx 被坠落的铁砧压扁了 block_explosion —— xxx 爆炸了 charging —— xxx 死了 contact —— xxx 被 xxx 杀死了 drowning —— xxx 淹死了 entity_attack —— xxx 被 xxx 杀死了 entity_explosion —— xxx 被 xxx 炸死了(xxx 爆炸了) fall —— xxx 落地过猛 falling_block —— xxx 死了 fire —— xxx 浴火焚身 fire_tick —— xxx 被烧死了 fireworks —— xxx 在一声巨响中阵亡了 fly_into_wall —— xxx 遭受了动态能量 freezing —— xxx 冻死了 va —— xxx 试图在熔岩里游泳 lightning —— xxx 被闪电击中 magic —— xxx 被 xxx 使用的魔法杀死了(xxx 被魔法杀死了) magma —— xxx 死了 none —— xxx 死了 override —— xxx 死了 piston —— xxx 死了 projectile —— xxx 被 xxx 杀死了 stctite —— xxx 被坠落的钟乳石刺穿了 stgmite —— xxx 被钉在了石笋上 starve —— xxx 饿死了 suffocation —— xxx 在墙里窒息而亡(需要目标实体卡在方块里才能使用此伤害类型,否则无法造成伤害) suicide —— xxx 死了 temperature —— xxx 死了 thorns —— xxx 死了 void —— xxx 掉出了这个世界 wither —— xxx 凋谢了 (上述信息来自官方附加包文档+作者自己测试得出) 附表2:\/damage历史 基岩版 1.18.10——加入了\/damage 第七十八章 event-生物事件 在第二十二章我们讲\/summon指令时,曾经提到了如下内容: 『生成事件严格来说叫做生物事件,是基岩版独有的东西。生成事件用于自定义一个生物或实体其生成后的行为,且该生成事件是支持该实体的,不然无法生效。一个生成事件参数只能填写一个生成事件。关于生成事件基岩版有一个专门的指令:\/event。』 那么这一章,我们就来讲一讲这个event的指令。 首先,我们具体了解一下,什么是生物事件(生成事件)呢? 我们知道,在mineceraft中,生物们会发生各种各样的事情,进行各种各样的行为,比如生物生成、村民四处游荡、末影人发怒等等等。这些发生在具体生物上的事情以及行为,我们就可以称之为『生物事件』。 『生物事件』一般由生物根据当前条件自行判断是否触发,但我们可以通过\/event指令来强制指定的生物触发某些事件,比如直接让小村民长大、让僵尸村民变成村民等等。 所以接下来,我们切入正题,来看看\/event指令的具体使用方法。 \/event 作用:使指定的生物触发指定的生物事件 存在版本:基岩版1.16.100-今 需要权限等级:基岩版-1 需要作弊:是 格式: \/event entity <目标生物><生物事件> 这条指令其实十分简单,你只需要指定谁要触发什么生物事件即可。举个简单的例子: \/event entity @e[type=pig] minecraft:on_saddled 这条指令会让所有猪触发事件『minecraft:on_saddled』,也就是使得所有猪戴上鞍。 再来一个例子: \/event entity @e[type=tnt_minecart] minecraft:on_instant_prime 这条指令将会让所有tnt矿车立马爆炸。当然,如果你想,也可以直接用summon生成一个立即爆炸的tnt矿车: \/summon tnt_minecart ~~~ minecraft:on_instant_prime 既然这条指令那么简单,所以本章自然就水(划掉)写不下去了。本章到此为止。 附表1:常用的生物事件(生成事件)一览表 minecraft:bee_angry ——使得实体生气(适用于末影人、狼等) minecraft:gain_bad_omen ——玩家得到不祥之兆的效果 minecraft:clear_add_bad_omen ——玩家停止得到不祥之兆的效果 minecraft:mand_block_activate ——命令方块矿车被激活 minecraft:crystal_explode ——末地水晶爆炸 minecraft:entity_spawned ——实体自然生成 minecraft:from_vige ——使铁傀儡生成自村庄 minecraft:on_instant_prime ——tnt矿车被激活并立即爆炸 minecraft:on_prime ——tnt矿车被激活 minecraft:on_saddled ——使得猪或炽足兽已经装备上鞍 minecraft:on_tame ——使得实体已被驯服(适用于猫、狼等) minecraft:resupply_trades ——村民为交易补货 minecraft:start_exploding ——苦力怕开始爆炸 minecraft:start_exploding_forced ——苦力怕正在准备爆炸 minecraft:stop_exploding ——苦力怕停止爆炸 minecraft:turn_<颜色英文>——潜影贝变为指定颜色 viger_converted ——僵尸村民变为村民 附表2:\/event历史 基岩版 1.16.100——加入了\/event ...... ...... ...... ...... ...... ...... ...... ...... ...... ...... (以下情节均为虚构,如有雷同,纯属巧合) 近期,在一个我的世界网易版服务器中,服主由于一个不小心,让苦力怕把主城给炸出了一个角。于是服主痛定思痛,关闭了『生物破坏』的游戏规则。 但没过几天,投诉的消息就在qq群里面炸开了锅,许多玩家反应说村民不种地了,不繁殖了,它们作为一个“资本家”(划去)玩家绝对不能容忍村民这样偷懒,生产队的驴都没这么歇过。还有玩家反应说雪傀儡怎么不产雪了。甚至还有玩家反应说末影龙怎么不破坏方块了,这样子难度太简单,不过瘾。 于是服主只好重新打开了『生物破坏』这个游戏规则,但苦力怕的问题仍然需要解决。如何使得苦力怕不会破坏方块呢?这个问题成为了服主的心头之患。 为了解决这个问题,他询问遍了每个管理员,每个管理员都说把这游戏规则关掉就行了。这样的态度使得服主十分生气——当服管理员,总共有五位,他非常想罢免四位;六个建筑师,他非常想罢免三位。 本来已经对苦力怕想要顺其自然的服主,偶然间遇见了一位玩家。这位玩家告诉服主,苦力怕如果炸不了,不就无法破坏方块了吗。服主恍然大悟,他很快去问管理员:有没有一种办法,能够让苦力怕无法爆炸? 这个管理员查了一下,不知道从哪里搞来一串指令给了服主。服主按照管理员的说法一试,效果十分显着。这条指令是什么呢? \/event entity @e[type=creeper] minecraft:stop_exploding ——重复运行、常加载区块、保持开启 第七十九章 结构方块 上 (本章已于2022\/7\/19~20日重写) (本章写作时,作者使用的是基岩windows10版1.19.10、基岩android版1.19.10、java版1.12.2和java版1.19) (强烈推荐在游玩minecraft时阅读此章) (本章的内容由于和指令没有太大关系,所以并不会讲得很详细) 在本书的第二章,我们详细地了解了一个在minecraft中十分重要的功能性方块:命令方块。 过了这么多章的第七十九章,也就是这一章,我们将会介绍第二个在minecraft中也很重要的一个功能性方块:结构方块。 什么是结构方块?要了解结构方块,首先我们得清楚:结构是什么? 结构(structures)在广义层面上来讲,是指由单个或多个方块组成的特殊的整体,比如村庄、埋藏的宝箱、玩家建造的泥土房等等,都属于结构。狭义层面上来讲,结构指的是生成结构(generated structures),即指『在世界创建界面的「生成建筑」选项关闭时会被禁用的任何结构』,如海底神殿、沉船、村庄都是『生成结构』。 『结构方块』这里的『结构』,就是广义层面上的意思。而『结构方块』本身,也就是一个能够让玩家保存或加载结构的一个功能性方块。 \\\\方块简介\\\\ 结构方块(structure block) 数字id:255[je1.13前]或252[be] 命名空间id:structure_block (je1.11版本之前为『structure』) 亮度:0 爆炸抗性: 具有标签: #dragon_immune(免疫末影龙破坏) #wither_immune(免疫凋零破坏) 数据值[仅be]: 0——数据 1——储存 2——加载 3——角落 4——结构模型 5——3d导出 \\\\具体介绍\\\\ 首先让我们来获取结构方块: \/give @s structure_block ——java1.11及以上版本和基岩版 \/give @s structure ——java1.11以下版本至1.9版本 不出意外的话,你应该获取到了一个十分紫并带有白色花纹的方块(紫颂果?),这个方块就是结构方块。放下来,然后打开它。和命令方块一样,打开结构方块也需要你满足一定的权限要求,否则无法打开。 结构方块和命令方块一样,有多种模式。但是和命令方块不一样的是,结构方块的模式在两个minecraft版本间(java版和基岩版)并不统一,有许多不一样的地方。 结构方块一共有五种模式,其中有三个模式在两个版本都有: 储存模式——用于从游戏世界中储存结构 加载模式——用于加载结构至游戏世界中 角落模式——帮助快速选择要储存的结构范围 数据模式[仅java版]——用于在自然生成结构时进行特殊的操作 3d输出模式[仅基岩版windows10版本]——用于从游戏世界中导出结构为3d模型 —1储存模式 储存模式(save mode),即用来储存结构的模式。在基岩版中,你打开结构方块默认就是这个模式。在这个模式中有如下的选项: 结构名称——你要将结构保存为什么名称?可以加上命名空间,不加的话默认的命名空间是『minecraft』(java版)或『mystructure』(基岩版)。比如你可以填写『my_vige』、『mine:hello』,前者会将结构保存为『minecraft:my_vige』或『mystructure:my_vige』,后者会直接保存为『mine:hello』。 相对位置——这和目标选择器的基准点有些像,你可以通过指定相对于结构方块位置的偏移量来指定用来选取结构的轮廓起始点。比如(0,2,0)就类似于~~2~,即向上偏移2格。 结构大小——你可以把它看作是目标选择器的dx、dy和dz参数,即用来指定基于结构轮廓起始点的选取轮廓大小。只不过和dx、dy、dz参数不一样的是,这并不能指定一个小于1(基岩版)或小于0(java版)的数,也就是说必须是一个正整数或自然数。比如(2,2,2),就相当于基于结构轮廓的起始点,沿着xyz三个轴的正方向,选取2x2x2的范围,你也将会看到一个棱长为2的正方体轮廓。 需要注意的是,在java版结构最大不能大于48x48x48,在基岩版最大不能大于64x384x64。 探测结构大小和位置(探测)——这是一个按钮,用来探测同名的角落模式结构方块来快速选取结构,我们会在下一章讲到这个的用法。 包括实体(包含实体)——这是一个开关,可以让你选择在保存结构时是否要连带实体也保存了。 保存——这是一个按钮,当你确认无误之后点击这个按钮,游戏就会将结构保存为对应的名称。在java版,这将会把结构保存为一个文件,你可以通过如下路径找到这个结构文件: 存档根目录\\generated\\<命名空间>\\structures\\<名称>.nbt \/\/java1.13及以上版本 存档根目录\\structures\\<名称>.nbt \/\/java1.13以下版本 在基岩版,这将会把结构保存至存档的数据库中,而不是一个文件。但别担心,基岩版还有『加载』按钮可以用来导出结构为文件。 上面的这些选项都是双版本通用的,接下来我将介绍双版本并不通用的一些选项: 重置[仅基岩版]——这是一个按钮,可以让你将结构方块里面的参数恢复为你刚打开时的样子。 移除方块[仅基岩版]——这是一个开关,打开后可以使得保存结构时不保存方块。 红石存储模式[仅基岩版]——这是一个选项,你可以选择『存储在内存中』和『存储至磁盘』两个选项,默认是『存储在内存中』。存储在『内存』,也就是临时保存临时用,存档退出即销毁。存储在『磁盘』,也就是永久性的保存,存档退出后不会销毁且还可用。这并不会影响到你手动保存结构,这只会影响到你用红石信号激活结构方块时它保存结构的方式。 显示边界盒[仅基岩版]——这是一个开关,默认打开,关闭后可以取消高亮即将存储区域的轮廓。 导出[仅基岩版]——这是一个按钮,可以让你将结构导出为.mcstructure类型的文件。但需要注意的是,这个按钮仅在windows10上的基岩版可用,mojang虽然说在android版本中也更新了这个东西,但由于一些奇妙的bug并不可用,在其他版本如ios版就根本没有这个功能。 显示隐形方块[仅java版]——这是一个开关,打开可以显示出一些隐形的方块:光源方块[黄色]、结构空位[粉色]、屏障[红色]和空气[蓝色]。 你可以尝试自己保存一些东西,比如保存你的房子之类的。 —2加载模式 加载模式(load mode),也就是用来将结构加载到游戏中的模式。在java1.17及以上版本,你打开结构方块默认就是这个模式。这个模式有如下的选项: 结构名称——不用说了吧?填写你要加载的结构名称,不填命名空间默认就是minecraft或mystructure。在java版,你还可以填写一些游戏自带的结构名称来生成游戏内的结构,我们会在下一章介绍你该如何生成这些结构。 相对位置——将要加载结构的起始位置,和『存储模式』的相对位置一样,只不过从保存变成加载功能了而已。 显示边框(显示边界盒)——这是一个开关,默认打开,会显示结构的轮廓。在java版,你需要先按一遍『加载』按钮来让游戏读取结构的内容,即预加载。预加载之后才会显示出结构轮廓,此时再按一遍『加载』就会真的将结构加载出来了。在基岩版,游戏会自动帮你预加载,所以你不用按两遍『加载』来加载结构。 结构完整性及种子——其实就相当于输入一个百分比,选择加载结构时仅随机加载多少方块。填的数值越低,最终加载出来的方块就越少,结构完整性越低。在java版,值可以填写0.0~1.0,基岩版则可以填写0.0~100.0。 包括实体——这是一个选项,选择是否要连带结构中保存的实体也加载出来。 旋转——在java版,这将会使得结构绕着起始位置顺时针旋转指定的度数。在基岩版,这将会使得结构绕着自己的中心顺时针旋转指定的度数。可以选择0°、90°、180°和270°四个度数。 镜像——在java版,可以选择三个选项:|(无镜像)、←→(以起始位置为原点,相对于x轴镜像)、↑↓(以起始位置为原点,相对于z轴镜像)。在基岩版,可以选择结构是否要基于自己的中心相对于x轴或z轴镜像(也可以两个都选)。如果你同时选择了镜像和旋转,那么游戏会先让结构镜像,再让结构旋转。 加载——也就是加载结构。如果结构还未预加载(也就是没有显示出边框或边框未更新),将会先预加载结构,而不是直接将结构加载出来。 移除方块[仅基岩版]——这是一个开关,选择加载结构时是否不要加载方块。 动画模式[仅基岩版]——这是一个选项,可以选择『无』、『按照层数放置(逐层放置)』和『按照方块放置(逐块放置)』。 动画时长[仅基岩版]——如果指定了动画模式,那么在这边可以填写动画的时长,也就是游戏要多长时间慢慢地把结构加载出来。该参数以秒为单位。比如你选择了『按照层数放置(逐层放置)』,并指定了10秒,那么游戏就会慢慢地从下到上一层一层地加载结构。 现在你可以尝试将自己刚刚保存的结构在另外一个地方加载出来。需要注意,如果游戏已经开始加载结构,但是是以动画的方式缓慢加载,你也不能通过敲掉结构方块来中断加载进程。 由于篇幅有限,本章就先介绍这两个模式(其实这两个模式就是最重要的两个模式了)。我们下一章会介绍剩下的三个模式。 ....... ....... ....... ....... ....... ....... ....... ....... minecraft不可能同时运行两个指令,所以在一游戏刻中运行的指令,也有先后之分。这些微小的时差,就叫做微时序。 微时序不管是在指令还是在隔壁红石,都有着极其重要的作用。所以这跟结构方块有什么关系? 『按照方块放置(逐块放置)』的动画模式,其加载方块的顺序,你可以去研究研究。或许,以后当我们正式讲到微时序时,就会提到类似的加载顺序。 第八十章 结构方块 下 (本章已于2022\/7\/20日重写) (本章写作时,作者使用的是基岩windows10版1.19.10、基岩android版1.19.10、java版1.12.2和java版1.19) (强烈推荐在游玩minecraft时阅读此章) (本章的内容由于和指令没有太大关系,所以并不会讲得很详细) 在上一章,我们了解了结构方块五个模式中最重要的两个模式:储存和加载。这一章,我们将会了解剩下的3个模式:角落、数据和3d导出。 —3角落模式 角落模式(corner mode)和储存模式的结构方块是互相配合的。在储存模式的结构方块中,有一个『探测』按钮,可以快速地通过同名的角落模式结构方块检测结构的大小和位置。 那到底怎么使用呢?举个简单的例子: ████████?█ ███▓▓▓▓▓██ ██?███████ 其中,?代表着储存模式的结构方块,?代表着角落模式的结构方块,阴影部分代表我们要保存的结构。 我们只需要在储存模式中,写上结构要存储成的名称,比如填写『my:str』,然后在角落模式结构方块中的『结构名称』参数也写上『my:str』,最后使用『探测』功能,游戏就会以这两个结构方块的位置分别作为两个顶点构成一个长方体,这个长方体就是储存的区域。游戏也会自动更新储存模式结构方块中的相对位置和大小两个参数。最后,你只需要按下『保存』就可以将结构存储下来。 你也可以使用两个角落方块来选取区域: ████████?█ █?█▓▓▓▓▓██ ██?███████ 在这里,你只需要确保两个?都写上了相同的『结构名称』,并且和?的一致,最后使用『探测』功能,游戏就会自动以这两个?为顶点来选取区域。 需要注意的是,角落方块选取的区域不能超过游戏规定的上限,也不能是一个2维甚至是1维的区域(即长宽高都不能为0)。并且,如果有超过两个同名的角落方块,虽然游戏也能选取,但选取的区域会有些奇怪。 —4数据模式[仅java版] 数据模式(data mode)主要的用途是用来自然生成结构,虽然说在java1.17以下版本结构方块的默认模式都是数据模式,但它对于玩家的用处其实并不大。 数据模式的结构方块只有一个参数:自定义数据标签名称。你虽然能够填写一些参数,但其实你并不能自己触发数据模式的结构方块,这只能由游戏在自然生成的过程中触发。 所以即使截止java1.19版本,数据模式对于玩家来说也没有任何用途。但是,对于游戏来说,这东西有着很大的用途。数据模式内填写的东西是游戏内自带的函数,游戏触发数据模式结构方块时其实就是触发指定的函数,然后对诸如箱子之类的东西进行修改,比如放上战利品表之类的。如果玩家也能够使用数据模式来触发函数,那这个数据模式瞬间就变得十分有用,上限就变得无限大啊! 所以作者这边就埋个坑,看看mojang以后到底会不会允许玩家使用数据模式。 —53d输出模式[仅基岩版windows10版本] 3d输出模式(3d export mode)有些类似于存储模式,只不过它并不是储存结构,方便玩家以后生成,而是直接将游戏内的结构导出为3d模型文件,以用于其他地方,比如动画制作、手办制作等等。 需要注意的是,该模式仅仅适用于基岩版的windows10版本(当然,windows11也能用,毕竟是套壳windows10[滑稽])。 该模式有如下几个选项: 相对位置——不用讲了,同存储模式 结构大小——也不用讲了,同存储模式 移除方块——也不用讲了 显示边框——还是不用讲 导出——将选取的区域以3d模型文件.glb导出 导出后,你可以使用一些3d模型软件来打开文件,如画图3d、3d viewer等等。你甚至还能导入到photoshop等专业软件里面进行操作,可谓是minecraft二创开发利器。 回到正题。现在,结构方块的五个模式我们都知道怎么用了,但有个东西我们还没讲: 如何生成游戏自带的结构呢? 让我们先来到你的游戏版本目录,找到你游戏的jar文件: .minecraft\\versions\\<游戏名称>\\<游戏名称>.jar 至于怎么找到.minecraft文件夹,我们在第六十三章已经研究过了。 接下来,用压缩软件打开这个jar文件,找到如下位置: 文件根目录\\data\\minecraft\\structures\\ 在这个structures文件夹里面,就放着游戏自带的各种结构文件。在java1.19版本的jar文件中,这个目录下有这么几个文件夹: ancient_city bastion end_city fossil igloo her_fossils piger_outpost ruined_portal shipwreck underwater_ruin vige woond_mansion 不难发现,这每个文件夹都对应了游戏内的一个结构,如vige对应村庄,end_city对应末地城等等。 打开其中的文件夹,你会发现.nbt后缀的结构文件和更多的文件夹。我们这边就以ruined_portal目录下的portal_1.nbt文件为例。在游戏中打开结构方块,调整为加载模式,然后输入结构名称为:ruined_portal\/portal_1。接下来点击加载,你就会惊喜的发现生成了一个废弃地狱门!还有宝箱! 废弃地狱门的宝箱由于在结构保存的时候就带有了loot标签(战利品表的nbt标签),因此不需要数据模式的结构方块就能够加载出战利品。如果你加载的是其他类型的如村庄的结构,就会发现它们的箱子大多上面都顶着一个数据模式的结构方块。 最后,让我们了解一下『结构空位』。 你在加载结构时,就算是空气也会替代原本的方块,那该如何使得原本的方块不被替换呢? 使用结构空位(structure void)就能够解决这个问题。 结构空位是一个方块,其id为minecraft:structure_void。当你在保存一个结构时,结构内的结构空位虽然也会被保存,但游戏在加载结构时并不会将结构空位加载出来,也就是说结构空位所在的地方会被游戏忽略并保留原本的方块。所以,适当的使用结构空位,可以防止我们的结构在生成时破坏其周围的地形。 (奇妙的是,在基岩版,结构空位被视作为一个完整的方块,这就使得火把之类的东西能够插在上面,然后结构空位又是隐形的、能够让实体通过的.......) 这就是结构方块的全部内容了。 附录:结构方块和结构空位历史 java版 1.9——加入了对于玩家来说没有任何用处的结构方块 1.10——结构方块可以让玩家使用了。加入了结构空位。 1.11——更改id从structure至structure_block 1.13——结构保存的位置从『存档根目录\\structures』改到了『存档根目录\\generated\\<命名空间>\\structures』。 1.14——结构空位的渲染颜色被更改。 1.16——结构的最大尺寸从32x32x32增加到了48x48x48 1.17——默认模式从数据模式改到了加载模式,并隐藏了数据模式,只能在按住alt键的情况下才能被切换到。结构空位的渲染颜色再次被更改。 携带版\/基岩版 1.0.0——加入了具有功能但完全无法获得的结构方块和结构空位。 1.2.0——结构方块现在能够获得,并具有了唯一的模式:3d输出模式。只不过,该模式仅在windows10和ios版本中可用。 1.5.0——结构方块能在andorid和ios版本中获取了,但无法使用。 1.9.0——移除使用remix3d导出选项,结构改为本地导出 1.13.0——在ios和android版本中,结构方块能够在开启『实验性玩法』的前提下使用。结构空位能够获得了。 1.16.0——结构方块和结构空位不再属于『实验性玩法』,并加入了『检测』按钮。 1.17.0——结构方块现在能够指定加载结构的动画 1.17.30——结构方块现在有了角落模式 第八十一章 structure-指令与结构方块 (本章已于2022\/7\/20~21日重写) 在前面两章,我们迅速的学习了一下结构方块的大致使用方法。但这结构方块跟指令有什么关系呢?结构方块也就只有一个玩家无法使用的『数据模式』才能和指令扯上边。 虽然结构方块和指令没有什么直接的关系,但在基岩版却有一条指令和结构方块的功能很有关系。它就是:\/structure \/structure 作用:和结构方块差不多。储存、加载或删除已保存的结构。 存在版本:基岩版1.16.100-今 需要权限等级:基岩版-1 需要作弊:是 格式: \\\\储存\\\\ \/structure save <结构名称><起点坐标><终点坐标>[存储方式] \/structure save <结构名称><起点坐标><终点坐标>[保存实体:布尔值][存储方式][保存方块:布尔值] \\\\加载\\\\ \/structure load <结构名称><区域基点>[旋转角度][镜像方式][加载实体:布尔值][加载方块:布尔值][结构完整度][种子] \/structure load <结构名称><区域基点>[旋转角度][镜像方式][动画模式][动画时长][加载实体:布尔值][加载方块:布尔值][结构完整度][种子] \\\\删除\\\\ \/structure delete <结构名称> 仔细看一下上面的格式,你就会发现除了\/structure指令多了一个delete的功能外,其他的功能结构方块都有。所以我们这边就不需要详细的学习了,我们只需要讲一下一些参数即可。 和结构方块不一样的是,structure选取结构是采用类似于\/fill指令的『<起点坐标><终点坐标>』,即指定两个坐标来选取区域,比如下面的例子: \/structure save grass ~1 ~1 ~1 ~-1 ~-1 ~-1 这将会把执行地点周围3x3x3的空间全部保存起来到内存中。 而structure加载结构就像\/clone指令选取要复制到的位置,都是采取指定『区域基点』坐标的方式。这『区域基点』也就是指你要复制到的区域中,xyz三个轴值最小的地方,也就是所谓的『下西北角』。 『存储方式』参数可以填写两个值:memory(保存在内存中[默认])和disk(保存至磁盘)。比如: \/structure save grass ~1 ~1 ~1 ~-1 ~-1 ~-1 memory 这将会把执行地点周围3x3x3的空间全部保存起来到内存中。 需要注意的是,如果你在内存中和磁盘中都保存了同样名称的结构,游戏在加载或保存过程中,如果未指定是从『内存』还是从『磁盘』,游戏就会优先选取内存中的结构。比如你将一个村民的家保存到磁盘中的『home』结构,然后将你的家保存到内存中的『home』结构,如果运行下面的指令: \/structure load home ~~~ 这将会加载出你的家,而不是村民的家。只有当你退出重进游戏之后,上述指令才会加载出村民的家。 『旋转角度』参数有些特别,它并不是直接填写度数,而是填写『0_degrees』、『90_degrees』、『180_degrees』和『270_degrees』。举个例子: \/structure load home ~~~ 270_degrees 假如你还没有退出重进游戏,那么上面的指令将会加载出你的家,并且会以结构的中心顺时针旋转270°。 『镜像方式』参数和execute的align子命令有些类似,它能够填写四个值:『none』(没有镜像)、『x』(对于x轴镜像)、『z』(对于z轴镜像)、『xz』(对于x和z轴镜像)。当然,它并不能填写『zx』,也就是不能乱排。举个例子: \/structure load home ~~~ 270_degrees xz 这将会加载出一个相对于x、z轴镜像的,顺时针旋转270°的你家。 『加载\/保存实体:布尔值』和『加载\/保存方块:布尔值』两个参数就不必说了,填写true(开启)或false(关闭)即可。 『结构完整度』参数和结构方块的『结构完整度』一模一样,都是填写一个0~100(含)的数。『种子』参数就更不必说,随便写都行,反正游戏会帮你转化。比如: \/structure load home ~~~ 270_degrees xz true true 90 what_is_up 这将会加载出一个相对于x、z轴镜像的,顺时针旋转270°的,只有90%完整度的,种子为『what_is_up』的你家。 『动画模式』参数可以填写两个值:block_by_block(按照方块放置)yer_byyer(按照层数放置),并不能选『无』。只不过你不填写『动画模式』参数的话,不就不会有动画了吗。『动画时长』参数也是指定加载动画的时长,单位也是秒。举个例子: \/structure load home ~~~ 0_degrees none block_by_block 20 这将会在20秒内一个方块一个方块地把你房子搭建出来。 最后,让我们尝试删除保存着你房子的结构,来实现不重进游戏也能够加载村民的房子: \/structure delete home 然后你就会发现一件事情——村民的房子也被删掉了。 没错,delete子命令不会管你是内存还是磁盘,只要有叫这个名称的结构就会删掉。也就是说,运行上述指令,会同时删除掉内存和磁盘中的home结构。 这就是本章的全部内容了。 附表:\/structure历史 基岩版 1.16.100——加入了\/structure 1.16.210——\/structure新增了delete子命令,可以删除已保存结构 第八十二章 fog-迷雾 我们知道,在minecraft中,玩家视野的边缘是由一个个区块组成的。但为什么我们一般不会看到棱角分明的区块,而是只会看到圆润的天边呢? 答案很简单——mojang为了优化玩家体验,在玩家视野的边缘套上了一层迷雾。 在白天时的主世界仔细观察天边,你就会发现尽管天空是湛蓝的,但天边的颜色却是浅蓝的,浅蓝往上和湛蓝有一个较为明显的过渡分界线。这个分界线就是迷雾和天的分界线,往下是迷雾,往上是天。 那有没有什么东西能够更改天和迷雾的颜色呢?或许有些人更喜欢红色的天空? 你可以通过材质包来修改天的颜色,甚至把天改成一些奇怪的图片都行,但是迷雾可不关材质包什么事情。那对于迷雾我们该怎么办呢? 在基岩版,你可以使用\/fog指令,来为指定的玩家添加上指定的迷雾效果。不同的迷雾效果具有不同的颜色,这样子就可以实现更改迷雾的颜色。 \/fog 作用:更改指定玩家的迷雾效果 存在版本:基岩版1.16.100-今 需要权限等级:基岩版-1 需要作弊:是 格式: \/fog <目标玩家> push <迷雾id><迷雾设置id> \/fog <目标玩家> pop <迷雾设置id> \/fog <目标玩家> remove <迷雾设置id> fog命令有三个子命令:push、pop和remove。这三个子命令看起来很奇怪,不应该是常有的『add、set和remove』吗?怎么变成了『push、pop和remove』了? 这你就得去问mojang了,看看它们发了什么神经,给fog子命令多弄了两个不明所以然的子命令。 回到正题,这三个子命令分别的作用如下: push——将指定的迷雾效果推送并添加到目标玩家指定的迷雾设置中 pop——移除目标玩家指定的迷雾设置中最后一次推送的迷雾效果 remove——移除目标玩家指定的迷雾设置以及设置中包含的所有迷雾效果 那么\/fog子命令到底该怎么使用? 首先,你需要指定一个目标玩家,比如你自己,然后使用push子命令,指定要推送的迷雾效果,再指定要将这个迷雾效果添加到哪个迷雾设置中,最后运行指令,你指定的迷雾效果就会被推送并添加到你自己的指定的迷雾设置中。比如下面的指令: \/fog @s push minecraft:fog_forest forest 这将会把『森林生物群系』的迷雾效果,推送并添加到『你自己』的叫做『forest』的迷雾设置中。 你可能会有些疑惑——给玩家添加迷雾效果我懂,但为什么还有一个叫做『迷雾设置』的东西? 其实,mojang考虑得相当周到,他们认为你可能需要用到许多个迷雾效果,而迷雾效果这东西又是可以添加许多个的,于是mojang就允许你指定要添加迷雾到哪个『迷雾文件夹』当中去,每个『迷雾文件夹』中可以添加一堆迷雾效果,且允许重复。每名玩家可以允许拥有一堆『迷雾文件夹』,来方便管理迷雾。需要注意的是,每名玩家最多只能同时拥有16个迷雾效果(不管有多少个迷雾文件夹)。 所以,上面的那串指令,我们就可以看作是:将『森林生物群系』的迷雾效果,添加到你自己所拥有的叫做『forest』的迷雾文件夹中(如果没有这个文件夹则会先创建)。 当然,『迷雾文件夹』只是一个为了方便你理解的说法,实际上游戏并不会真的给你创建一堆文件夹,然后里面塞满了各种各样的迷雾文件。 所以你能够理解吗?如果你能够理解上面的内容,那么下面的内容就简单了。 我们拥有一定的管理『迷雾文件夹』的方法。比如,我么可以使用pop子命令来移除指定『迷雾文件夹』中最后一个被添加的迷雾效果: \/fog @s pop forest 这将会移除掉你刚刚添加进去的minecraft:fog_forest迷雾效果。 我们还可以使用remove子命令来删除整个文件夹: \/fog @s remove forest 这将会删除掉『forest文件夹』及其里面的所有迷雾效果。 现在你会用fog命令了吧?但你有没有发现,我们虽然添加了迷雾效果,但天边的迷雾怎么没有改变颜色啊? 其实迷雾不仅仅会影响到天边迷雾的颜色,它还会影响到水体的颜色,以及水中的迷雾。而大多数种类的迷雾,其实只会影响到水中迷雾的颜色。 比如:\/fog @s push minecraft:fog_desert miwu 这将会给你自己的『miwu迷雾设置』中添加上沙漠的迷雾效果,如果你在陆地上你会发现添加前和添加后没有任何变化,但如果你跑水里去你就会发现水变绿了。 如果此时我们再添加一个迷雾效果呢?比如: \/fog @s push minecraft:fog_warm_ocean miwu 这将会添加上『暖水海洋』生物群系的迷雾效果,然后你就会发现由于『暖水海洋』的迷雾效果也指定了水中迷雾的颜色,后者就把前者的效果覆盖了,水变成了蓝色(当然,这个蓝色比没有任何迷雾效果的水要蓝一些)。 让我们用\/fog @s remove miwu来移除掉刚刚添加的两个迷雾效果。既然大多数种类的迷雾只会影响到水中迷雾的颜色,那么剩下的能够影响天边颜色的少数迷雾有哪些呢? 其实主要就两个: minecraft:fog_hell ——地狱迷雾效果(天边变红) minecraft:fog_the_end ——末地迷雾效果(天边变黑) 我们来试一试: \/fog @s push minecraft:fog_hell try 这将会给我们自己的『try迷雾设置』中添加上地狱迷雾效果,如果此时你在白天的主世界,那么你就会明显的发现天边变红了,而且迷雾在迅速的朝你围拢过来。但天还是湛蓝的,和天边的红色十分不搭,此时该怎么办呢? 其实,如果我们把minecraft的天空拆分,那么迷雾就是在最底层,天空是在第二层,太阳、星星和月亮在第三层。如果我们要把迷雾全部显示出来,就要把天空、太阳、月亮和星星全部移除掉。为了达到这样的效果,其实你只需要打开设置,找到『视频设置』下的『美丽的天空』选项,关掉,你就会发现整个天空都变成红色的了。 对了,如果我们这时候再次尝试添加其他迷雾效果会发生什么事情?比如: \/fog @s push minecraft:fog_desert try 然后你就会发现天边的颜色并没有变化,还是红色的。 不对啊,不是说好会覆盖的吗? 其实覆盖了,只不过由于『沙漠』生物群系的迷雾效果仅仅规定了水中迷雾的颜色,因此只是覆盖了水中迷雾的颜色而已,天边颜色并未覆盖。 最后,让我们来了解一些常用的迷雾效果: minecraft:fog_default ——默认迷雾效果 minecraft:fog_desert ——沙漠迷雾效果(水中变绿) minecraft:fog_swamnd ——沼泽迷雾效果(水中变暗绿) minecraft:fog_river ——河流迷雾效果(水中变得更蓝) minecraft:fog_mushroom_ind ——蘑菇岛迷雾效果(水中变暗粉) minecraft:fog_crimson_forest ——绯红森林迷雾效果(天边、水中变红) minecraft:fog_basalt_deltas ——玄武岩三角洲迷雾效果(水中、天边变暗粉) minecraft:fog_hell——地狱迷雾效果(天边、水中变红,天边迷雾距离变近) minecraft:fog_the_end——末地迷雾效果(天边变黑,水中变紫,水中迷雾距离变近) 这就是本章的全部内容了。 附表:\/fog历史 基岩版 1.16.100——加入了\/fog 第八十三章 bossbar-自定义boss栏 上 (此章节已于2022年7月22日重写,重写时作者使用的是java1.19版本) 我们在第七十二章讲execute的存储子命令时,曾经遇到过这么一个子命令: bossbar ——将值存储到boss栏中 当时我们并没有学过bossbar的使用,所以就略过了这个子命令。 那么bossbar是什么呢?如何使用?能干什么?这就是我们这两章所要了解的内容。 首先,什么是boss栏(bossbar)呢? 当你前往末地,或是生成一个凋零,你就会发现在屏幕的上方出现了一个粉色的血条,这就是boss栏。 只不过boss栏虽然叫做『boss栏』,但它的用处不仅仅是表现boss的血量,它还有很多其他的用处,比如在村庄劫掠中用来当做劫掠的进度。 在java1.13及以上版本,你可以通过一条指令来使用boss栏: \/bossbar 作用:添加、修改或删除boss栏 存在版本:java1.13-今 需要权限等级:java-2 需要作弊:否 格式: \/bossbar add <名称:json文本> \\\\添加一个boss栏\\\\ \/bossbar get [max|yers|value|visible] \\\\返回boss栏的某些值\\\\ \/bossbar list \\\\列出当前所有boss栏\\\\ \/bossbar remove \\\\移除一个boss栏\\\\ \/bossbar set (name|color|style|value|max|visible|yers) ... set name <名称:json文本>——设置boss栏名称 ... set color <颜色>——设置boss栏颜色 ... set style <样式>——设置boss栏分段数 ... set value <值>——设置boss栏的值 ... set max <最大值>——设置boss栏的最大值 ... set visible <是否显示:true|false>——设置boss栏的显示状态 ... set yers <目标玩家:目标选择器>——设置对谁显示boss栏 不难发现,一个boss栏有很多属性,如名称、id、值、最大值、颜色等等,这些属性除了id外都可以通过bossbar的set子命令更改,大部分也能通过get子命令返回。只不过,我们得先创建一个boss栏: \/bossbar add server_owner “腐竹“ 这将会创建一个id为『minecraft:server_owner』,叫做『腐竹』的boss栏。 你并不会马上看到刚刚创建的boss栏,因为此时boss栏虽然处于显示状态,但并没有目标玩家,也就是没有对谁显示出这个boss栏。让我们稍微设置一下: \/bossbar set server_owner yers @s 这将会设置成向我们自己展示『腐竹』boss栏,然后你就会发现这个刚刚建立的boss栏是灰色的,值为0。这可不行,让我们来改一下它的颜色和值: \/bossbar set server_owner color pink \/bossbar set server_owner value 100 第一条指令将会设置boss栏的颜色为粉色,也就是和末影龙、凋零同样的boss栏颜色。第二条指令将会设置boss栏的值为100,因为默认boss栏的最大值就是100,所以设置为100的话boss栏就满了。 boss栏支持七种颜色:blue、green、pink、purple、red、white和yellow,默认颜色为white(白色)。只不过因为刚刚boss栏值为0,导致颜色暗度变大,我们就看到了灰色。 不出意外的话,经过上面的设置,你应该会看到一个『满血』的腐竹boss栏。我们可以尝试一下set子命令的其他功能,来个性化boss栏: \/bossbar set server_owner name {“selector“:“@p“} 这将会把boss栏的名称改为距离指令执行地点最近玩家的名称,其中的『selector』json聊天组件我们会在以后专门讲json时遇到(其实已经在基岩版的json中遇到了)。 \/bossbar set server_owner style notched_20 这将会把boss栏的样式改为:20段,也就是这个boss栏在视觉上会被分为20段。 boss栏的样式参数支持5个值:progress(连续[默认])、notched_6(分六段)、notched_10(分十段)、notched_12(分十二段)、notched_20(分二十段)。 \/bossbar set server_owner max 20 这将会把boss栏的最大值改为20。相应的,boss栏的值也会减到20。 \/bossbar set server_owner visible false 这将会隐藏boss栏。 上面这些就是set子命令的全部用法,看起来功能很多,但其实相当的简单。至于其他的子命令就更加简单了,我们来举些例子: \/bossbar get server_owner value 这将会返回『腐竹』boss栏当前的值。 \/bossbar get server_owner yers 这将会返回『腐竹』boss栏的目标玩家以及其数量 \/bossbar remove server_owner 这将会移除『腐竹』boss栏。 可见,bossbar这东西虽然有很多功能,但其实易于理解,很好上手。所以本章就到这里,相信你已经懂得如何使用bossbar这条指令了。 附表:bossbar历史 java 1.13 ——加入了\/bossbar (\/bossbar list会列出游戏本身的boss栏吗?) (当然不会啦,mojang哪里会给你这样的空子去钻) 第八十四章 bossbar-自定义boss栏 下 (此章节已于2022年7月22日重写) 在上一个章节,我们创建了一个id为minecraft:server_owner,叫做『腐竹』的boss栏。这个boss栏是粉色的,分成20段,最大值为20。虽然看起来很厉害,但有一个问题——这个boss栏没有实际用处。 所以在这一个章节,我们要让这个boss栏发挥出实际的用处,使得服主的血量能够实时反映到这个boss栏上。 既然要能够实时反映,我们就要解决两个问题: 1如何实时获取到服主的血量 2如何将服主的血量存储到boss栏的值中 首先来看第一个问题,这个问题其实很好解决,我们有两种简单的办法:1使用nbt标签,直接获取2创建一个health准则的计分项,然后获取服主在这个计分项上的值 第一个方法我们暂且没有学过,但第二个你总该会吧?让我们来试一试: \/scoreboard objectives add health health 这将会创建一个health准则的叫做health的计分项,然后你就不用管了,游戏会自动把每个玩家的血量存储到这个计分项上。让我们来看一看游戏弄得如何: \/scoreboard objectives setdisy sidebar health 这将会在右侧边栏显示出health计分项,然后你会发现——怎么空空如也? 其实游戏仅仅会在玩家血量变化的时候记录血量的值到计分板上,由于此时计分项才刚创建,还没有任何一名玩家的血量发生变化,计分项自然就空空如也。你可以尝试摔一次跤,正常情况下右边就会正确显示出你的血量。 计分项弄好后,我们就可以通过以下指令获取到服主的血量: \/scoreboard yers get fuzhu health (其中,fuzhu代表服主的游戏名称) 第一个问题就这样解决了,但还有第二个问题:如何将服主的血量存储到boss栏的值中 在这边,我们就得使用execute存储子命令的bossbar子命令,其格式如下: ... store <返回类型> bossbar (value|max)... id参数,也就是要存储到的boss栏的id;『(value|max)』参数,也就让你选择要将返回的结果存储到该boss栏的值还是最大值中。在这边我们当然是要存储到值(value)中,也就是使用如下指令: \/execute store result bossbar minecraft:server_owner value run scoreboard yers get fuzhu health 上面的指令将会把『scoreboard yers get fuzhu health』返回的结果,也就是服主的血量,存储到id为『minecraft:server_owner』的boss栏的值中,这样子boss栏就可以显示出服主当前的血量了! 我们只需要将这条指令放入一个一直重复执行的命令方块中,就可以实现『服主的血量实时反映到这个boss栏』这样的效果。 最后我留个作业,你感兴趣的话可以尝试实现实现。 作业内容:在本章内容的基础上,利用所学知识,实现下面描述的效果 1如果服主不在线,隐藏boss栏,在线的情况下再显示出来。 2服主周围一定范围内的玩家会看到『腐竹boss栏』,超出这个范围的玩家则无法看到 3在服主自己的血量上限提升的情况下(比如有伤害吸收或生命提升的药水效果),也要相应提升boss栏的最大值 其中,第三点要完美实现的话需要一定的nbt知识,如果你并不不了解,也可以用计分板做一个勉勉强强的效果出来。 这就是本章的全部内容。 第八十五章 item-更高级的replaceitem 在第三十八章中,我们了解了\/receitem的使用方法。可惜这么一个厉害的指令,却在java1.17版本中被移除。只不过你并不需要担心,因为取而代之的是一个更加厉害的指令——item。 item比receitem少了一个单词rece(替代),这说明了item的功能不仅仅局限在替代物品,还有一些其他的功能。具体有哪些其他功能呢?让我们来看看item这个指令的格式,你就知道了: \/item 作用:修改方块或实体物品栏内的物品 存在版本:java1.17-今 需要权限等级:java-2 需要作弊:否 格式: \/item modify ... ... block <方块坐标><栏位><物品修饰器id> ... entity <目标实体><栏位><物品修饰器id> \\\\为指定方块或实体的指定栏位内物品添加指定的物品修饰器\\\\ \/item rece ... ...(block <方块坐标>|entity <目标实体>)<栏位>... ...... with <物品id>[数量] \\\\修改指定方块或实体的指定栏位内的物品为指定的物品\\\\ ...... from (block <方块坐标>|entity <目标实体>)<栏位>[物品修饰器id] \\\\修改指定方块或实体的指定栏位内的物品为另一个方块或实体内指定栏位内的物品\\\\ 不难发现,相比以前的\/receitem,新的\/item不仅仅保留并升级了rece替代的功能,还新增了一个modify为物品添加修饰器的功能。 我们先来看看遗传下来的替代功能。新版本的替代功能不仅仅可以替代某个物品栏位为指定的物品,还可以把另外一个容器内的物品复制过来 我们先来试试传统的功能:替代某个物品栏位为指定的物品。比如我们要将自己帽子栏位内的物品替换为一个tnt,就需要使用: \/item rece entity @s armor.head with minecraft:tnt 1 我们来对比一下上述指令在1.17版本前的写法: \/receitem entity @s slot.armor.head minecraft:tnt 你会发现两者总体的变化并不是很大,最主要的变化也就是在『栏位』参数和『物品id』参数间多出了一个with,这个with的作用是用来告诉游戏:我仅仅只是指定一个要替换成的物品而已,也就是使用传统的替换功能。还有一个比较小的变化就是,栏位id前面没有『slot.』前缀了。 我们现在来看看新的替换模式:from复制模式 item新添加的『复制模式』要指定两个物品栏位,第一个栏位是目的地,第二个栏位是来源。比如: \/item rece entity @s armor.head from entity @s weapon.offhand 这将会把你副手(weapon.offhand)所持有的物品复制到你的头上。第一个指定的『entity @s armor.head』即目的地,第二个指定的『entity @s weapon.offhand』即来源。 再来一个例子: \/execute as @a at @s if block ~~-1 ~ minecraft:furnace run item rece block ~~-1 ~ container.2 from block 35 65 26 container.0 这将会把所有玩家脚底下熔炉输出槽内的物品替换为坐标为(35,65,26)的容器的第一个槽位内的物品。假设这个容器是一个箱子,箱子的最左上角放着三颗钻石,那么运行上述指令过后,所有玩家脚底下熔炉的输出槽内都会有三颗钻石。(注:箱子最左上角的栏位id为container.0,熔炉输出槽栏位为container.2) 还是比较简单的嘛。接下来我们来看看item添加的全新功能:物品修饰器。 什么是物品修饰器呢?简单来说,物品修饰器里面设定了一些程序,这些程序会对物品本身进行一些修改。我们可以通过item命令给指定栏位内的物品添加上一个物品修饰器,然后这个物品就会被物品修饰器所修饰。 举个例子,假设有一个id为『arcaea:kill_tairitsu』的物品修饰器,这个物品修饰器会对物品本身进行一些修改,使得该物品在攻击名为『tairitsu』的实体时能够发挥出超强的攻击力。我们可以通过以下指令给我们主手上的物品添加上这个物品修饰器: \/item modify entity @s weapon.mainhand arcaea:kill_tairitsu 这将会给我们主手拿着的物品添加上这个物品修饰器,然后你就能拿着这个物品去挑战名为『tairitsu』的实体了。 虽然物品修饰器功能强大,但它和谓词一样,都是数据包才有的,原版并没有任何的物品修饰器。因此如果你要使用物品修饰器,首先你就得弄一个具有物品修饰器的数据包出来。 这就是本章的全部内容了。 附录1:java1.17新版本槽位id 箱子、陷阱箱、发射器、投掷器、漏斗 container.<槽位编号>——从左到右、从上往下、从0递增 酿造台 container.0-2 ——底部从左到右 container.3 ——顶部 container.4 ——烈焰粉槽位 熔炉 container.0 ——输入 container.1 ——燃料 container.2 ——输出 实体 armor.chest ——胸 armor.feet ——脚 armor.head ——头 armor.legs ——腿 weapon.mainhand ——主手 weapon.offhand ——副手 container.<槽位编号>——??? enderchest.<槽位编号>——末影箱 hotbar.<槽位编号>——快捷栏 inventory.<槽位编号>——玩家背包 horse.saddle ——鞍的槽位 horse.chest ——(羊驼、骡或驴)驮着的箱子 horse.armor ——马铠或地毯的槽位 horse.<槽位编号>——驮着箱子的羊驼、骡和驴 viger.<槽位编号>——村民或猪灵的背包 附录2:\/item历史 java 1.17——加入了\/item 第八十六章 music-音乐 (本章重写时作者使用的是minecraft windows10基岩版1.19.10版本) (本章节有许多内容由作者自己实验或寻找得出,在minecraft wiki上可能并未记载,或是与minecraft wiki上的记载有些许出入。如遇问题,请以minecraft wiki上的内容为准。——2022\/7\/23 作者注) 我们在第六十三章中,讲到了一条控制声音的指令:\/ysound。但在基岩版,还有一条和\/ysound很类似的指令,这条指令同样也是用来控制声音,只不过具体点说,是控制音乐。这条指令就是: \/music 作用:控制音乐 存在版本:基岩版1.16.100-今 需要权限等级:基岩版-1 需要作弊:是 格式: \/music y <音乐名称>[音量][淡入淡出时间:秒][播放模式] \\\\播放指定的音乐\\\\ \/music queue <音乐名称>[音量][淡入淡出时间:秒][播放模式] \\\\将指定音乐加入到待播放列表中\\\\ \/music stop [音乐淡出时间:秒] \\\\停止播放音乐\\\\ \/music volume <音量> \\\\调整播放音量\\\\ 和\/ysound不一样的是,指令\/music仅仅只能控制执行者自己的游戏背景音乐。又因为同一时间内又不能播放多首游戏背景音乐,所以\/music虽然作用和\/ysound很像,但两者的格式却大不一样,深层次的效果也不一样。 minecraft基岩版的游戏背景音乐播放器简直就像是一个音乐软件,拥有『当前正在播放的歌曲』和『播放清单』,你可以指定播放的『音量』大小,还能够设置播放的模式是『顺序播放』还是『单曲循环』模式等等。只不过,『minecraft音乐』这款软件的控制方法和其他音乐软件大不一样,你需要使用minecraft内置的『命令行』应用——指令——来控制这款软件。 先让我们停止一下游戏自动给我们“推送”的音乐: \/music stop 这将会停止执行者自己,也就是我们自己的minecraft正在播放的背景音乐,并清除『播放清单』内的所有音乐。然后我们就可以尝试让游戏播放一些指定的歌曲。 问题来了:怎么知道我们可以播放什么音乐呢? 这时候我们就需要请出那个大名鼎鼎的文件:sound_definitions.json 还记得这个文件吗?我们在第六十三章中,起码花费了超过四分之一的篇幅来讲解如何找到这个文件,相信你应该还记得吧?让我们重新把那个文件找出来,或者上minecraft wiki查找也行。 使用文本编辑器打开这个文件(当然如果装了一些诸如vs code的软件更好),你就会再一次看到一大堆的你大概率看不懂的东西。别担心,对于\/music指令来说,这里大多数都是废话。\/music指令能播放的音乐只认两种: 1声音名称开头为『music.』的 2声音名称开头为『record.』的 使用ctrl+f或mand?+f开启查找模式,搜索『music.』或『record.』,你应该能够找到一些结果,比如『music.menu』(游戏主界面音乐)或『record.cat』(唱片c418 - cat的音乐)。这些音乐就是可以被\/music所播放的音乐。让我们来试一试: \/music y music.gameher 这将会先停止当前播放的音乐并清除『播放清单』内的所有音乐,然后再播放下界的背景音乐。只不过由于『music.gameher』这个音乐名称指定了多个音乐,所以游戏会从中随机播放一首。不出意外的话,你应该会听到一些很小声的不同的音乐,这就是下界的背景音乐。 现在,游戏的『播放清单』只有一首我们刚刚添加进去的音乐,让我们再添加一首: \/music queue music.game.swamp_music 这可能是沼泽生物群系的音乐。如果你对mc音乐比较熟的话可以仔细听一听,看看这到底放的是什么音乐。这个音乐并不在sound_definitions.json这个文件内,而是在它旁边的music_definitions.json这个文件内(你应该有看到这个文件)。 music_definitions.json这个文件可能是用于指定生物群系的特定背景音乐,比如你来到森林就播放森林的音乐,来到沼泽就播放沼泽的音乐......但有一点可以肯定的是,\/music也可以播放该文件中event_name字段所指定的声音名称。 总之,上面这条指令将会把这个音乐添加到游戏的『播放清单』当中,等到下界的音乐播放完,游戏就会自动继续播放沼泽生物群系的音乐,直到把『播放清单』内所有音乐播放完,游戏才会重新切回默认的背景音乐。 我们还可以添加一些参数来指定音乐的音量和淡入淡出时间。 『音乐』参数的值是一个介于0.0~1.0(含)的浮点数,举个例子: \/music y record.blocks 1.0 这将会以1.0(100%)的音量播放c418 - blocks这个唱片的音乐。当然,这条指令同样也会切断当前正在播放的音乐,并清空『播放清单』。 『淡入淡出时间』和『音乐淡出时间』两个参数其实都是一样的,其值是一个介于0~10(含)的整数,单位为秒。举个例子: \/music y record.wait 1.0 10 这将会以最大的音量播放c418 - wait这个唱片的音乐,并且游戏会在音乐开始播放前以及结束播放后空出10秒时间不播放任何音乐以实现『淡入淡出』的效果。 (ps:当你使用\/music播放record.开头的音乐时,其实就相当于使用\/ysound在指令执行地点向你自己播放了个一样的音乐,因此你跑远的话照样会听不到音乐) 最后,『播放模式』可以指定两个模式,即: y_once ——只播放一次,即『顺序播放』,这是默认模式 loop ——洗脑循环模式,即『单曲循环』 举个例子: \/music queue record.mall 1.0 0 loop 这将会在『播放清单』上添加c418 - mall唱片的音乐,游戏顺序播放到这个音乐时就会不断重复播放这个音乐,直到你使用stop子命令停止播放或者退出游戏。 最后,让我们来尝试改变一下当前正在播放的背景音乐的音量: \/music volume 0.5 这将会把当前正在播放的背景音乐的音量调整到50%。 本章到此为止。 ——附表1:\/music可用的声音清单(作者自己整理,可能不全) 唱片音乐 record.13 record.cat record.blocks record.chirp record.far record.mall record.mellohi record.stal record.strad record.ward record.11 record.wait record.5* record.pigstep* record.otherside* 生物群系音乐 music.game.deep_dark music.game.swamp_music music.game_and_wild_equal_chance music.game_and_wild_favor_game music.game.lush_caves* music.game.dripstone_caves* music.game.grove* music.game.jagged_peaks* music.game.lush_caves* music.game.meadow* music.game.frozen_peaks* music.game.snowy_slopes* music.game.stony_peaks* music.game.basalt_deltas* music.gameher_wastes* music.game.soul_sand_valley* music.game.warped_forest* music.game.soulsand_valley* music.game.crimson_forest* 普通背景音乐 music.menu music.game music.game.creative music.game.water music.game.end music.game.endboss music.gameher music.game.credits (ps:其中标上星号『*』的音乐代表着这个音乐并不是从vani目录下找到的,而是从各版本的vani目录下找到的) ——附表2:\/music历史 基岩版 1.16.100——加入了\/music 第八十七章 拼图方块 (此章节原本为『战利品(\/loot 上)』,2022年7月24日重写为『拼图方块』) (作者重写时使用的是minecraft java1.14.4、1.16.2、1.19和基岩版1.19.10) 我们在第七十九章至八十章,了解了一个特殊的方块:结构方块。结构方块可以用来生成整个结构,但在minecraft中,有许多诸如村庄、要塞之类的结构虽然整体上也是结构,但其实是由多个小模板随机组合而生成的。比如村庄,一个村庄就是由水井+一堆道路+一堆房子+一堆村民+一堆其他的东西组合而成。 既然结构方块能够生成结构,那么我们是否可以生成用来组成结构的模板(小型结构)呢? 答案是肯定的,你可以通过结构方块来生成模板,但往往这些模板生成出来后并不具有随机性,也就是说就算你会生成也没用。那我们该怎么办?能不能通过一些途径来使得这些模板像游戏自然生成一样生成? 俗话说的好:条条大路通罗马,mojang给了我们另外一条路——拼图方块。 拼图方块(jigsaw block) 数字id:-211[be] 命名空间id:jigsaw 亮度:0 爆炸抗性: 具有标签: #dragon_immune(免疫末影龙破坏) #wither_immune(免疫凋零破坏) 拼图方块虽然功能比结构方块要少很多,但要上手这东西难度可不是一般的大。首先,让我们来获得一个拼图方块: \/give @s jigsaw 然后你可以把它放下来。不难发现,拼图方块像命令方块一样,也具有箭头。但和命令方块不一样的是,拼图方块只有3面有箭头,而在原来应该有箭头的那一面,只有一个长度大约是半个方块长的白色直线。这个白色直线所在的这一面,就是这个拼图方块的正面。 和其他方块不一样的是,拼图方块具有12个朝向,这12个朝向分别是: 上东(箭头朝上,白色直线那一面朝东) 上西(箭头朝上,白色直线那一面朝西) 上南(箭头朝上,白色直线那一面朝南) 上北(箭头朝上,白色直线那一面朝北) 东上(箭头朝东,白色直线那一面朝上) 西上(箭头朝西,白色直线那一面朝上) 南上(箭头朝南,白色直线那一面朝上) 北上(箭头朝北,白色直线那一面朝上) 下东(箭头朝下,白色直线那一面朝东) 下西(箭头朝下,白色直线那一面朝西) 下南(箭头朝下,白色直线那一面朝南) 下北(箭头朝下,白色直线那一面朝北) 只不过我们目前暂且不需要管这么复杂的朝向,只需要能够分辨出拼图方块的箭头朝的是上下东西南北中的哪一个方向就行了。 打开拼图方块,这个操作需要你具有一定的权限。打开后,你应该看到了下面几个选项: ——java版 目标池: minecraft:empty 名称: minecraft:empty 目标名称: minecraft:empty 转变为: minecraft:empty 拼接类型:可旋转(ps:箭头朝上或朝下时才会显示出这个选项) 层数:0 |保留拼图:开|生成 完成|取消 ——基岩版 目标池: minecraft:empty 名称: minecraft:empty 目标名称: minecraft:empty 变为: minecraft:air 接点类型:可滚动 完成|取消 看起来选项很少,但如果你仔细一瞧,就会发现你似乎根本就不懂得如何使用这个玩意儿。事实上也的确如此。那么我们该如何使用拼图方块? 首先我们就要搞懂这四个空分别是指什么东西。 目标池(target pool),其实就是指要用来生成的模板\/结构池(你可以把这东西当作是一个装着许多结构[模板]的池子,游戏在生成时会随机拿一个结构[模板]出来生成)。需要注意的是,目标池填写的内容并不是直接精确到某个结构文件,而是精确到结构文件所在的文件夹。举个例子,你并不能这么写: minecraft:vige\/savanna\/houses\/savanna_small_house_1 这虽然对结构方块有效,但这对拼图方块没用,因为它直接精确到了savanna_small_house_1.nbt这个结构文件。你应该要填写的是: minecraft:vige\/savanna\/houses 这样子拼图方块才会认。 默认这是填写minecraft:empty,也就是没有东西可以生成。目标池为『minecraft:empty』的拼图方块你可以把它看做是一整个拼图的边缘,也就是不会再有什么新的部分了。 名称(name),即该拼图方块的名称。 目标名称(target name),指的是这个拼图方块要连接到的另一个拼图方块的名称。这就像是两块拼图,一块是a另一块是b,你必须要指定a是连接b的,否则a哪里知道自己需要被拼在哪里。需要注意的是,『另一个拼图方块』并不是说你在这个拼图方块a旁边再放一个拼图方块b,而是指拼图方块a所选择的目标池中的结构内所具有的拼图方块。如果你并不能很好理解上面的描述,那我举个例子: look!这是一个拼图方块,它叫做a,它的目标池是minecraft:vige\/savanna\/houses,连接的拼图方块叫做minecraft:building_entrance。 a→ 这是另外一个拼图方块,它叫做minecraft:building_entrance,我们暂且就称它为b。这个拼图方块在minecraft:vige\/savanna\/houses下一个结构里,这个结构是一个小房子,它就位于这个小房子的大门口: ←b门房 现在,玩家打开了a,选择了一个大于0的层数,然后点击了生成按钮,随后a从池子中抽到了b所在的那个结构!a随后检查了一下这个结构,它找到了它要连接的b!a很高兴,它在脑袋中臆想把b放在自己正前方的样子: a→←b (这是a的想象) a发现它们两简直是天之绝配,能够完美契合在一起!a太高兴了,它把b连带着b后面的房子也全部生成了出来: a→←b门房 至于a会不会和b成为朋友,领到结婚证,走上块生巅峰,那就是后话了。但可以肯定的是,『目标名称』即代表着一个拼图方块想要连接的另一个拼图方块,它就像是一块拼图上的提示,告诉游戏这个拼图方块会和结构中哪一个拼图方块拼接形成一个像是上面a和b贴贴的结构,所以这东西啊十分滴重要。 虽然a和b贴贴对于拼图方块来讲是件好事(如果能拟人化那就更是件好事),但这对于游戏来讲并不是件好事,对于玩家来讲那就更不是件好事——你敢忍受一个房子的门口被放上两块像基岩一样硬的方块吗?何况这两个方块还是成双成对,这对于很多不成对的人来讲那就更不友好。那么游戏是怎么解决这个问题的呢?很好解决:当这个拼图方块被使用了,也就是被拼了,游戏就会让它变成其他的方块。至于具体是什么方块,就得看这个拼图方块的『转变为(变为)』选项写的是啥了。 『转变为(变为)』选项默认填写的是『minecraft:air』,也就是空气方块。这代表着该拼图方块被使用过后就会变为空气方块。这里填写的方块id支持附加方块状态和方块实体(方块nbt),比如:『minecraft:acacia_stairs[facing=east]』就代表着该拼图方块会被替换为一个朝向东的金合欢木楼梯。 如果你能成功理解上面的内容,那么下面的内容就很简单了。 『拼接类型』和『接点类型』有两个选项:可旋转(可滚动)和固定(一致)。可旋转,即代表着该结构在生成时会随机旋转一些度数,当然这个度数肯定是90°的倍数。固定,即代表着这个结构在生成时不会旋转,只会以默认的朝向生成。 『保留拼图』选项,即代表着这个拼图方块生成结构后,被生成结构内的拼图方块(不包括生成结构的那个拼图方块)是否要保留下来。如果为『关闭』,则结构内的拼图方块在生成后会被替换为『转变为』指定的方块。放在上面的ab贴贴例子中,如果a关闭了『保留拼图』,那么b在生成后就不能和a贴贴了,b会被替换成空气或是一些其他的方块。 『生成』按钮,你按下去就会使得这个拼图方块尝试根据你指定的这些参数来生成结构,如果成功那就会生成一个结构,如果不成功那就不会生成。在基岩版和java1.16前的某些版本,由于拼图方块内没有『生成』按钮(你应该有注意到),导致你即使获得了,填写了正确的参数也生成不了,也许是因为功能还没做好mojang才这么搞的。 你有没有发现我似乎漏了一个选项:『层数』。 这个『层数』选项可以选择0-7的任意一个整数,但这有什么用呢? 让我们先来尝试使用结构方块生成村庄的道路——放置一个结构方块,使用加载模式加载『minecraft:vige\/savanna\/streets\/crossroad_02』这个结构,然后你就会看到加载出来了一些附带了许多拼图方块的道路。 不难发现,结构内也有一些其他的拼图方块,这些拼图方块也可以加载出更多的结构来和此结构结合。比如村庄,就是由拼图方块先加载出来一个道路结构,然后道路结构内的拼图方块又加载出更多的道路结构,同时也顺带加载出了房子、铁傀儡、田地、猫,房子的拼图方块又加载出来村民以及更多的东西......就这样套娃生成,最终形成了『阡陌交通,鸡犬相闻』的村庄。 当然,游戏不可能无限套娃生成出一个超大的村庄来,所以游戏就规定了『层数』,这个『层数』就是指能够套娃生成的层数,举个例子: 假设有一个结构池(目标池),id为『:some_』,其唯一的结构长这样: ←m草草草m→ m······名称为m,目标名称为s,目标池为『:a_huaji』,『保留拼图』为关闭的拼图方块 还有一个结构池(目标池),id为『:a_huaji』,其唯一的结构长这样: ←s稽稽 s······名称为s,目标名称为m,目标池为『:some_』,『转变为』是『:huaji_block』(滑稽方块)的拼图方块 现在有一个拼图方块←t,目标池为『:some_』,目标名称为『m』,『保留拼图』为开启。我们来打开t,调整生成层数为『2』,然后点击一下生成按钮,就会生成: 稽稽稽←m草草草m→←t 为什么会这样呢?让我们来分析一下。 首先这个t拼图方块会找到『←m草草草m→』这个结构,然后寻找叫做『m』的拼图方块。由于此时m有两个,所以t会随机选取一个,如果选取到的m朝向和t的相反朝向不一致,就会旋转整个结构使得m和t互相朝向对方(也就是让它们两能够贴贴),然后就生成了: ←m草草草m→←t 接下来游戏会继续套娃第二层。由于右边的m已经使用过了,所以游戏会激活左边的m,然后m找到『←s稽稽』这个结构,调整整个结构的朝向使得s能够和自己贴贴,就生成了: 稽稽s→←m草草草m→←t 但由于m关闭了『保留拼图』,加上现在第二层已经生成完了,规定也是生成到第二层,不会再生成第三层,所以s在生成后,游戏就会将s替换为『:huaji_block』,也就是滑稽方块,最终就变成了: 稽稽稽←m草草草m→←t 如果你听懂了,那么接下来我们来探讨几个问题: 1为什么『←m草草草m→』必须要有两个m?不能是『←p草草草m→』,然后让p指向s吗? 这样做也行,只不过你最终会生成出如下结构 ←p草草草m→←t 玩家使用拼图方块进行多层生成时,游戏仅仅会让结构中和初始拼图方块(也就是←t)目标名称一致的拼图方块(也就是叫做m的拼图方块)来生成结构,并不会让结构中所有的拼图方块都生成。当然,游戏自己使用时肯定没有这个限制。 2如果t的朝向是上或下会怎么样? 假设t的朝向是上,那么将不会生成,因为游戏无法弄出来这样的结构: 稽 稽 稽 ↑ m 草 草 草 m ↓ ↑ t 就算能够弄出来这样的结构,游戏也不会允许这样的结构生成。因为如果游戏允许,那么生成的情况就会更加复杂,毕竟有些方块可没有竖着的朝向。t朝下同理。 3如果t的层数选择了3甚至更高会发生什么? 这个问题由你自己去思考。 4基岩版能使用拼图方块吗? 因为没有『生成』按钮,所以你虽然能够填写参数,但是用不了(悲)。 这就是本章的全部内容。 附表:拼图方块历史 java 1.14——加入了拼图方块,可用于生成村庄和掠夺者前哨站。 1.16——具有了新的gui,可以用来生成堡垒遗迹。 1.19——可以用来生成远古城市。 基岩版 1.10.0——加入了拼图方块,没用 1.16.0——能够用\/give获得,并且有了gui和实际用途,但玩家还是用不了 第八十八章 place-如何生成一个村庄 在第八十一章,我们了解了基岩版中一条用来储存、加载和删除结构的指令:\/structure。那么在java版,有没有类似的指令呢? 并没有,但是有一条指令却拥有生成结构的功能。这个指令就是: \/ce 作用:放置地物、拼图、结构或结构模板 存在版本:java1.19-今 需要权限等级:java-2 需要作弊:是 格式: \/ce feature <地物id>[放置位置] \\\\在执行地点或指定位置放置一个地物\\\\ \/ce jigsaw <目标池><目标名称><层数>[生成位置] \\\\在执行地点或指定位置以拼图方块的模式生成结构\\\\ \/ce structure <结构id>[生成位置] \\\\在执行地点或指定位置生成一个结构\\\\ \/ce temte <结构模板id>[生成位置][旋转角度][镜像方式][完整度][种子] \\\\在执行地点或指定位置以指定的方式生成一个结构模板\\\\ 这个\/ce指令可以放置地物、拼图、结构和结构模板这四种东西,后三者其实本质上都是结构,唯独这个『地物』是什么? 地物(decorators)并没有一个明确的定义。大体来说,地物指的就是地上的一些东西,比如树、湖泊、植物丛、各种圆盘、远程折跃门等等,你能想到的、不能想到的基本上都可以算作是地物。 我们来尝试简单放置几个地物(注:请确保放置地点周围没有重要的东西,因为地物会覆盖大多数方块,甚至包括基岩): \/ce feature minecraft:birch ~~~ 这将会放置一颗普普通通的白桦树。 \/ce feature minecraft:bonus_chest ~~~ 这将会在你周围放置一个奖励箱。 \/ce feature minecraft:iceberg_blue ~~~ 这将会在你的位置(你最好飞起来)放置一个由蓝冰组成的冰山。 需要注意的是,地物基本上都有生成要求,如果没有达到要求则会放置失败,或看起来成功了但实际上没有放置。比如: \/ce feature minecraft:ice_spike ~~~ 这将会在你的位置上放置一个冰刺,但如果放置地点下方第一个非空气方块不是雪块的话将放置失败。 由于地物有很多,所以这里就不细讲了,你可以前往minecraft wiki的『命令\/ce(java版)』页面查看所有可使用的地物以及其生成条件。 jigsaw子命令看起来十分熟悉。没错,这不就是拼图方块嘛!只不过在这边是用命令替代了拼图方块的作用。拼图方块我们上一章才讲过,你应该还记忆犹新,让我们来试一下: \/ce jigsaw minecraft:vige\/savanna\/houses minecraft:building_entrance 1 ~~~ 这将会在指令执行地点以拼图方块的模式,从目标池(模板池\/结构池)『minecraft:vige\/savanna\/houses』中随机抽取一个模板(结构),然后对接该结构中叫做『minecraft:building_entrance』的拼图方块,并仅生成1层,最终就会生成一个热带草原村庄的房子或农田,并替换掉结构内所有拼图方块。 因为这个子命令和拼图方块的功能完全一样,所以这里也不细讲。 structure子命令应该是这个\/ce指令最令人激动人心的功能。通过它,你可以直接生成一个结构!举个简单的例子: \/ce structure minecraft:vige_ins ~~~ 这将会在命令执行位置(你的位置)生成一个平原上的村庄,也就是最普通的村庄。 最后的temte子命令有点类似于jigsaw子命令,但和jigsaw不一样的是temte可以直接生成结构模板(相当于直接用结构方块生成),不需要采用拼图方块那么复杂的模式来生成。举个例子: \/ce temte minecraft:vige\/savanna\/houses\/savanna_small_house_1 ~~~ 这将会在你的位置生成一个热带草原村庄的小房子。 但其实temte子命令并没有那么简单。请你往回翻一翻,仔细看一看这家伙后面的可选参数,想一想,你就会想到两个东西: 『结构方块的加载模式』和 『\/structure load子命令』! 没错,这家伙基本上等价于基岩版的\/structure load子命令,你可以通过它来生成你自己创建的结构!举个例子: 假设你自己创建了一个结构,叫做『minecraft:my_matchbox』,这个结构长这样: --第一层 土土土土土↑ 土土土土土z 土土土土土| 土土土土土| 土土土土土| ←x——— --第二层 土空土土土 土床空台土 土床空箱土 土空空空土 土土门土土 --第三层 土土土土土 土空火炉土 空空空箱土 土火空火土 土土门土土 --第四层 草草土土草 土土土土土 土土土草土 土土土土土 土土土土土 图例: 土······泥土 草······草方块 火······火把 空······空气 炉······熔炉 箱······箱子 台······工作台 床······白色床 门······橡木门 现在,我们尝试通过\/ce指令生成这个结构: \/ce temte minecraft:my_matchbox ~~~ none none 1.0 这将会以100%完整度、为种子在指令执行位置(也就是你的位置)生成一个没有镜像、没有旋转的『minecraft:my_matchbox』结构。 『旋转角度』参数可填写的内容和基岩版的大不一样,你可以填写: none——不旋转 clockwise_90——顺时针旋转90° 180——旋转180° counterclockwise_90——逆时针旋转90° 举个例子: \/ce temte minecraft:my_matchbox ~~~ counterclockwise_90 none 1.0 这将会以100%完整度、为种子生成一个绕着指令执行位置逆时针旋转90°(顺时针270°)的没有镜像的『minecraft:my_matchbox』结构,也就是变成下面这样: --第一、三、四层 略 --第二层 这里是没有↑ 逆时针旋转z 九十度且没| 有镜像的原| 本生成位置| ←x———| 土土土土土| 土台箱空土| 土空空空门| 空床床空土| 土土土土土| 『镜像方式』参数可填写的内容也不一样。你可以填写: none——无镜像 left_right——关于生成位置基点的x轴镜像(相当于结构方块中的←→) front_back——关于生成位置基点的z轴镜像(相当于结构方块中的↑↓) 举个例子: \/ce temte minecraft:my_matchbox ~~~ none front_back 1.0 这将会以100%完整度、为种子生成一个相对于放置位置z轴镜像且无旋转的『minecraft:my_matchbox』结构,也就是变成下面这样: --第一、三、四层 略 --第二层 这里是没有↑土土土空土 关于z轴镜z土台空床土 像且没有旋|土箱空床土 转原本应该|土空空空土 的生成位置|土土门土土 ←x———|—————— 『完整度』和『种子』参数就不讲了,很简单。 这就是本章的全部内容。 附表:\/ce历史 java 1.19——加入了\/ce,替代了\/cefeature ...... ...... ...... ...... \/cefeature 作用:放置地物 存在版本:java1.18.2-1.19 |基岩1.18.30 需要权限等级:java-2 基岩-1 需要作弊:是 格式: \/cefeature <地物id>[放置位置] 作用你应该知道,不讲了。 附表2:\/cefeature历史 java 1.18.2——加入了\/cefeature 1.19——移除了\/cefeature,改用\/ce feature 基岩版 1.18.30——加入又移除了\/cefeature 第八十九章 ride-骑乘 (该章节已于2022年7月25日重写,原章节为『战利品表(战利品表下)(\/loot 下)』) 我们知道,在minecraft中,玩家可以骑上马,骷髅可以骑上蜘蛛,僵尸可以骑上鸡......但不管怎样,我们都很难使用指令来控制实体的骑乘状态。在java版这尚且可以通过nbt做到,但在基岩版呢?基岩版可用不了nbt。 好消息是,基岩版虽然用不了nbt,但mojang却给了我们一条指令: \/ride 作用:控制实体骑乘 存在版本:基岩版1.16.100-今 需要权限等级:基岩版-1 需要作弊:是 格式: \/ride <骑手实体>... ... start_riding <坐骑实体>[传送模式][骑乘建立要求] \\\\使得指定的骑手骑在指定的坐骑上\\\\ ... stop_riding \\\\使得指定的骑手停止骑乘\\\\ ... summon_ride <实体id>[召唤要求][生成事件][实体名称] \\\\给骑手召唤一个坐骑,让骑手骑上去\\\\ \/ride <坐骑实体>... ... evict_riders \\\\使得指定的坐骑逐出它们的骑手\\\\ ... summon_rider <实体id>[生成事件][实体名称] \\\\给坐骑召唤一个骑手,让召唤出来的骑手骑在坐骑上\\\\ 通过\/ride指令,你可以指定实体骑或被骑在某些实体身上。让我们来试一试: \/ride @s start_riding @r[type=horse] 这条指令将会使你随机骑在某一匹马的身上。等等,@r不是用来随机选择玩家的吗,怎么能够拿来随机选择马? @r确实是用来随机选择玩家的,但在除了java1.13及以上版本之外,其他版本的@r都可以通过指定type参数来具体随机指定种类的实体。在上面的例子中,由于我们指定了type参数为马,所以@r[type=horse]在这边就是随机选择一匹马。 运行上述指令后,你虽然骑在了马身上,但同时也被传送了,毕竟游戏总不可能让你隔空骑马吧?但有时候可能你并不想被传走,而是想让那匹马自己过来,这时候该怎么办? 指定『传送模式』参数。这个参数可以填写两个值: teleport_ride——将坐骑传送至骑手 teleport_rider——将骑手传送至坐骑(默认) 举个例子: \/ride @s start_riding @r[type=horse] teleport_ride 这条指令将会随机一匹马传送到你下面,然后让你骑在它的身上。 『骑乘建立要求』这个参数适用于当你指定多个骑手时的情况,它可以填写两个值: if_group_fits——当所有骑手都满足骑乘要求时才会建立骑乘关系 until_full——给每一个满足骑乘要求的骑手建立骑乘关系(默认) 举个例子: \/ride @e start_riding @r[type=chicken] teleport_rider if_group_fits \/ride @e start_riding @r[type=chicken] teleport_rider until_full 假设现在有三个实体:你自己、一只成年僵尸、一只鸡。运行第一条指令,将不会发生什么,因为你不可能骑在鸡上面,鸡也不能骑在自己上面,@e选中的三个骑手中有两个不满足要求,自然僵尸也不会骑上去。运行第二条指令,僵尸就会骑到鸡的上面,因为虽然你和鸡都不满足要求,但僵尸满足了要求,自然就和鸡建立起了骑乘关系。(你干嘛~哎哟) 这个僵尸还有用,让我们把它从鸡上弄下来: \/ride @e[type=zombie] stop_riding summon_ride子命令可以直接生成一个实体作为坐骑,当然,如果骑手不符合被生成实体的骑乘要求,那么实体即使被召唤出来也不会被骑乘,仅仅只会单纯生成出来。还是以刚才的条件,举个例子: \/ride @e[type=zombie] summon_ride minecraft:boat 这将会给那位僵尸生成一艘船,然后让它坐进去。 『召唤要求』参数可以填写三个值: skip_riders ——仅仅为没有坐骑的骑手召唤坐骑 no_ride_change ——仅仅为没有坐骑且也没有被骑乘的骑手召唤坐骑 reassign_rides——为所有骑手召唤坐骑(默认) 举些例子: \/ride @e summon_ride minecraft:boat skip_riders \/ride @e summon_ride minecraft:boat no_ride_change \/ride @e summon_ride minecraft:boat reassign_rides 还是以上面的情况为条件。如果我们运行了第一条指令,游戏将会尝试给玩家(你自己)、鸡和船召唤坐骑,僵尸由于已经有一个船作为坐骑所以不会尝试召唤。 如果我们运行第二条指令,游戏将会仅给玩家和鸡召唤船作为坐骑。僵尸由于已经有坐骑、船由于被僵尸骑乘,所以两者都不会尝试召唤坐骑。 如果我们运行第三条指令,游戏将会给所有实体都尝试召唤坐骑。 当然,不管你运行的是上面哪条指令,最终结果都是你和鸡会坐上船,僵尸和僵尸的船不会发生变化。因为僵尸已经有一个船作为坐骑,再召唤的话,僵尸的新坐骑必定会插入到僵尸和船之间,骑着船也被僵尸骑,也就是得满足两个实体的骑乘要求。而船肯定不会被船骑乘,也不会骑着一个船,所以僵尸和船都不会发生变化。 evict_riders子命令可以使坐骑赶走自己的骑手: \/ride @e evict_riders 这将会使得所有实体赶走自己的骑手,也就是让你、鸡和僵尸都从船上下来。然后你就可以把船回收一下。 summon_rider子命令可以为一个坐骑生成骑手,举个例子: \/ride @e[type=zombie] summon_rider minecraft:zombie 仍然以上面的情况为条件,这条指令将会给那只僵尸生成一只新的僵尸,然后让新的僵尸骑在老的僵尸上面。 值得注意的是,由于成年僵尸也可以像幼年僵尸一样骑在成年僵尸上,这就给了我们一条途径在基岩版弄叠罗汉: \/ride @e[type =zombie] summon_rider zombie minecraft:as_adult 这将会给让所有僵尸尝试生成一个新的成年僵尸作为自己的骑手,然后.......你重复运行下试试? 这就是\/ride指令的基本用法,也就是本章的全部内容。 附表:\/ride历史 基岩版 1.16.100——加入了\/ride ...... ...... ...... ...... ...... ...... ...... ...... ...... 自然生成的僵尸,有5%的概率生成出一只幼年僵尸。幼年僵尸不可被成年僵尸骑乘,因此当指令『\/ride @e[type=zombie] summon_ride zombie』在目标选择器『@e[type=zombie]』只选择到一个僵尸的情况下生成出一只幼年僵尸时,指令将执行失败,返回的成功次数为0。 也就是说,上述指令有5%的概率执行失败。我们可以造一个命令模块验证一下这5%的概率: (指令版本:基岩版1.19,未开启实验性功能) a→b→c→d→e→f→g→ a[重][无][红]······ride @e[type=zombie,name=a] summon_ride zombie reassign_rides minecraft:entity_spawned b[链][限][始]······scoreboard yers add count test 1 c[链][无][始]······ride @e[type=zombie,name=a] stop_riding d[链][无][始]······execute @e[type=zombie,name=a]~~~ kill @e[type=zombie,r=6,name=!a] e[链][无][始]·······execute @e[type=zombie,name=a]~~~ kill @e[type=item] f[链][无][始]·······scoreboard yers add times test 1 g[链][无][始]······tp @e[type=zombie,name=a]-16 -60 0 \\\\图例\\\\ [重]重复;[无]无条件;[红]需要红石;[脉]脉冲;[限]有条件的;[始]始终活动;[链]连锁 \\\\使用到的计分项\\\\ test \\\\使用到的变量\\\\ count(指令成功次数)、times(指令执行次数) 上面的模块会不断重复执行『ride @e[type=zombie,name=a] summon_ride zombie reassign_rides minecraft:entity_spawned』这条指令,并计算出指令的成功次数和执行次数。经过运行,加上一点儿人工计算,就可以得到以下数据: 执行1784次,成功1699次,差值85,失败概率约4.76% 执行次,成功9488次,差值512,失败概率约5.12% 可见,概率差不多就是5%。 为什么我要提这东西呢? \/ride作为一个使得玩家能够控制实体骑乘的指令,竟然能够因为这个特性而用于概率计算中,挺令人惊讶的是不是?但其实,不管是对于指令还是隔壁红石来说,能够巧妙运用游戏本身的特性,就是进阶玩家的基本要求。\/ride只是一个例子,像这样的例子还有很多。特别是在基岩版,由于指令自由度没有java版高,这迫使得许多基岩版的指令玩家大显神通,通过许多看起来十分取巧的方法实现许多看似不可能实现的功能,这边举几个例子: 1通过玩家攻击隐形盔甲架来实现点击牌子、点击村民npc的效果 2通过tell指令能够使用目标选择器的特性,在tell指令中塞入大量的@e目标选择器并发送给指定玩家,来使得指定玩家游戏卡死以实现封禁的效果 3在java1.13版本前,由于没有能够读取nbt数据的指令,因此当时普遍的方法是通过选取具有特定nbt标签值的实体并给予指定标签或分数,并使用穷举的方法来实现读取nbt数据的功能 4通过testforblocks指令比较命令方块,来实现检测物品和玩家名是否一致 所以,有时候当你想实现一个功能时却不知道怎么实现,不妨放开脑洞,想一想一些指令的特性,或许你就有了思路! 本章到此完全为止。 第九十章 命名空间id (本章已于2022年7月25日修改) 你该如何通过\/give指令获取到一颗钻石? 在minecraft pc1.7.2(java版1.7.2)之前的版本中,物品只有数字id,加上目标选择器没有@s,所以你只能这样子获得钻石: \/give @p 264 对于原版来说数字id就够了,但这对于模组来说就很不友好。举个例子,工业时代2(industrial craft 2)模组添加了一个叫做『工业钻石』的物品,它的数字id为。为什么这个id要跑到这么后面?答案很简单:如果放在很前面的话,万一原版添加了个新的物品,或者某个mod也添加了id一样的物品,那游戏岂不是分分钟崩掉?所以对于minecraft1.7.2版本之前的模组来说,物品的id就得弄成一个大数以降低冲突的风险,防止玩家的游戏因为id冲突崩掉。 但随着minecraft玩家群体的增大,模组数量的增多,原版那一丁点儿id分配空间就显得捉襟见肘了。mojang官方估计也注意到了这一点,于是自1.7.2版本开始,mojang开始尝试放弃数字id,转为使用更加先进的:命名空间id。 什么是命名空间id?这个名词其实我们在第八章已经遇见过了,你也知道它大概长什么样: xxxxxxxxx:xxxxxxxxx 命名空间id(namespaced identifier),又称资源路径(resource location)或命名空间字符串(namespaced string),是minecraft中一种为了正确识别到特定对象而尽量不产生歧义和冲突的一种方式。它普遍的格式如下: 命名空间:名称 不难发现,一个命名空间id由左边的命名空间和右边的名称id组成,两者使用英文半角冒号『:』分开。 在java版,命名空间和名称只能含有阿拉伯数字『0』、小写字母(旧版本也能含有大写字母)『abcdefghijklmnopqrstuvwxyz』、下划线『_』、连字符『-』和点『.』,在名称中还能够使用正斜杠『\/』。 在基岩版,命名空间和名称能够含有除英文半角冒号『:』和正斜杠『\/』以外的所有字符,但有一些特殊情况:在战利品表和函数名称中,正斜杠『\/』也可以使用。 『命名空间id』中的『命名空间』是什么?有什么用呢? 回到上面的钻石例子。我们现在有一个数字id为264的钻石,但如果此时有另外一个模组也添加了一个相同id的物品,也叫做『钻石』,这时候264这个数字id就代表着两个物品:原版的钻石和这个模组的钻石。这时候游戏就会出现混乱,不出意外的话应该会崩掉。那么我们该如何解决这个问题呢? 要解决这个问题,我们就要找到一种方式,能够区分这两个『钻石』。区分的方式有很多,比如可以判断两个钻石引用的材质文件,可以判断两个钻石的代码,但万一材质也是同一个文件该怎么办?代码一模一样怎么办?我们必须找出一个最容易方便辨别的,也最不容易相同的,且两个钻石都具有的东西来判断。 这个东西究竟是什么呢? 假如你在某个b 站上发表了这么一句话来表达你宏大的志向: 『我是胡桃的狗!』 问题来了,这个『胡桃』指的是哪个胡桃呢?是《原神》的胡桃,还是《胡桃日记》的胡桃,还是东方旧作的胡桃,还是《公主连结》的胡桃,甚至是属于植物的胡桃? 不难发现,我们在描述不同的『胡桃』时,往往会在前面加上定语『xxx的』,其中xxx往往是某一个更高层面的东西,『的』用来区分两者。等等,让我们把『的』换成冒号,然后你就会发现: 原神:胡桃 胡桃日记:胡桃 东方project旧作:胡桃 公主连结:胡桃 植物:胡桃 虽然字符用的是中文,不符合minecraft java版的规范。但如果抛开这点来说,这完完全全不就是『命名空间id』吗?!其中『原神』、『胡桃日记』、『东方project旧作』等就是『命名空间』。 但是这还不足以解释『命名空间』,让我们再换一个例子。 张三的电脑上有两个文件夹a和b,两个文件夹都具有一个叫做『music.mp3』的文件。由于这两个文件在不同的文件夹下面,因此不会发生冲突,计算机能够正常识别它们。如果它们是在同一个文件夹下面,那么计算机识别的时候就会发生混乱,可能会直接跳出那个众所周知的蓝色窗口。在这边,文件夹『a』和『b』就代表命名空间。 但是我们仍然不能够清楚解释『命名空间』究竟是什么。其实,『命名空间』本身也并没有一个很准确的定义,它在不同的场合可能具有完全不同的意义,比如种类、游戏、公司、文件夹、数据库、国家、学科等等等等。当然,如果你的抽象思维比较好的话,你当然可以把它想象成一个空间,至于这个空间究竟是什么你不用去管。同样的名称在不同的空间被赋予上不同的意义,并且不会和其他名称发生冲突,因为两个名称虽然一样,但处于不同的命名空间之中。 回到最开始的钻石例子,你应该已经想到如何区分原版和模组的钻石吧?这两个钻石就算本身完全一样,但它们所处的『空间』并不一样。其中一个钻石是『原版的钻石』,另外一个钻石是『模组的钻石』。我们只需要对比两个钻石所处的『空间』,也就是对比拥有这两个钻石的两个东西即可。mojang和其他第三方模组开发者也是这么想,所以在minecreaft java1.7.2版本中引入的命名空间,就是这么干: minecraft:diamond \\\\我的世界的钻石\\\\ mod:diamond \\\\模组的钻石\\\\ 如今,随着版本的更迭,『命名空间id』正在被用于越来越多的东西上。截止minecraft java1.19.1和基岩版1.19.10版本,在原版中,命名空间已经用于这些东西: 方块、方块实体[je]、液体[je]、物品、实体种类、生物记忆[je]、画[je]、村民职业[je]、村民种类[je]、状态效果、药水效果[je]、魔咒、粒子种类、维度[je]、生物群系、统计[je]、配方种类[je]、配方序列化器[je]、声音、战利品表、函数、进度[je]、谓词[je]、结构、配方[je]、标签[je]、方块状态文件[be]、模型[be]、纹理[be]、boss栏[je]、命令存储[je]、命令参数[je]、战利品表函数[je]和战利品表种类[je]。 这不列没事,一列出来吓一大跳,这么多。其实,一些第三方模组加载器早已为更多的东西加入了『命名空间id』。比如在sponge forge海绵模组服务端中,为指令加上了『命名空间id』。未来,随着mojang官方对数据包、行为包、附加包等『官方模组』的持续支持,原版游戏内必定会有更多的东西用上『命名空间id』。 所以,你现在清楚『命名空间id』是什么了吗?让我们重新获取一遍钻石,加深一下你对这东西的理解: \/give @s minecraft:diamond 本章到此为止。 附表1:『命名空间id』历史 java 1.6.1——加入了『命名空间id』和命名空间minecraft 1.7.2——命令现在能够使用『命名空间id』 1.8——几乎所有命令现在不再接受数字id 1.11——命名空间id现在不允许使用大写字母,并加入了字符限制 1.13——命名空间id现在变为唯一可以被接受的id形式,数字id被完全移除 1.14.4——客户端资源包加入了realms命名空间 1.16——实体的属性现在也使用命名空间id 携带版\/基岩版 1.12.0——加入了命名空间和minecraft前缀,使得附加包能够向游戏内添加新的东西 附表2:dinnerbone对命名空间id的评论 this isn''t a new concept, but i thought i should reiterate what a “namespace“ is. most things in the game has a namespace, so that if we add something and a mod (or map, or whatever) adds something, they''re both different somethings. whenever you''re asked to name something, for example a loot table, you''re expected to also provide what namespace that thing es from. if you don''t specify the namespace, we default to minecraft. this means that something and minecraft:something are the same thing. 这不是一个新概念,但是我想我应重申一下什么是“命名空间”。游戏中的大多数东西都有一个命名空间,以便在我们加入了something的同时一个mod(或地图,或其他)也加入了something时来区分它们两个。当您要为某个东西命名时,例如一个战利品表,您还需要指定这个东西所属的命名空间。如果您不指定命名空间,我们默认它是minecraft。这意味着something和minecraft:something是一回事。 ——原文来自『 ——翻译来自中文minecraft wiki 第九十一章 红石比较器 (此章节原为『循环装置-牛顿的棺材板快要按不住了啊!!!』,于2022年7月26日改为『红石比较器』) (此章节有用到本章说来插入图片,因此最好在起点中文网上阅读本章) 现在我们已经了解了很多指令,但是仅仅知道各种指令如何使用,最多也就称得上是一个『会用指令的玩家』而已。那该怎么办呢?我们现在要做的是,将各个指令和游戏特性互相联系起来,这也就是这一卷的主要内容。 红石比较器(redstone parator),你应该知道这是个什么东西吧?作为红石电路的重要组成部分之一,它有许许多多的的用途。 作者的红石并不怎么好,所以这边并不会讲什么特别高深的红石相关内容(我也不会讲)。但基础的一些特性我们还是要了解了解。 让我们拿出一个红石比较器,放在地上,你应该注意到了这东西上面插着三个看起来像是红石火把的东西(其实就是红石火把),并组成了一个三角形(△)。这个三角形的一边平行于红石比较器的一侧,另一头指向另一侧(见插图91-1)。 这个三角形意味着什么呢?让我们换一个方式来看待红石比较器: ┏━┓北 ┃△┃↑(插图:91-2) ┗━┛ (长方形的红石比较器?) (额,就这样子将就看吧,能够看配图的话那更好) 这是一个朝向正北(z-)的红石比较器,这个红石比较器有三个输入口和一个输出口: ┏o┓ b△c(插图:91-3) ┗a┛ a······后侧输入口 b······左侧输入口 c······右侧输入口 o······输出口 其中,a后侧输入口是很重要的一个输入口,你可以向这个输入口输入红石信号。当然,单纯的输入红石信号并不会发生什么事情,因为我们没有在o输出口放置一些能够接收红石信号的东西。让我们在a侧放置一个红石块,o侧放置一个红石粉看看: 亮起来的红石粉 ┏o┓ b△c(插图:91-4) ┗a┛ 红石块 你会发现o侧的红石粉亮起来了。这是为什么? 因为红石比较器在a侧收到了红石块产生的红石信号,于是就从o侧输出来了。那么问题来了:我们都知道红石信号有强度等级之分,在普通的红石线中传递的红石信号每过一格就会衰减一级,直到完全没有信号。那么红石信号在穿过红石比较器的过程中会发生衰减吗? 由于红石块能够产生出15级的红石信号,因此我们只需要测试o侧输出的红石信号是否为15级即可。我们当然可以通过延长o侧的红石线路,观察红石信号是否传递了15格。但别忘了本书是一个指令教程,因此我们干脆直接用指令对o侧的红石粉进行方块状态测试: \/execute if block ~~~ minecraft:redstone_wire[power=15]——java1.13及之后版本 \/testforblock ~~~ minecraft:redstone_wire [power=15]——java1.12.2-1.11 \/testforblock ~~~ minecraft:redstone_wire [“redstone_signal“:15]——基岩版 虽然方块状态我们并没有了解过,但也快了,这边先预习一下也无妨。上面的指令的作用是:探测指令执行地点(也就是你的位置)的方块是否是红石线,且power(redstone_signal)方块状态的值为15。其中,power(redstone_signal)方块状态的作用就是储存该红石粉的红石信号强度等级。 站在o侧的红石粉上,根据你的版本选择性运行上面的指令。如果指令运行成功,那么就代表着这个红石粉具有15级的红石信号,也就验证了我们上述的猜想。那么实际情况怎么样呢? 指令确实运行成功了。 这意味着什么呢?这意味着,红石比较器不会导致红石信号的衰减。但随之而来就有另一个问题——红石比较器会像红石中继器一样增强信号吗? 让我们再测试一下,将上面的结构改成下面这样: ┊——究竟是14级还是15级? ┏o┓ b△c(插图:91-5) ┗a┛ ┊——14级红石信号 ┊——15级红石信号 ? 图例 ┊······红石线 ?······红石块 然后还是老样子,对o侧的红石线进行方块状态测试,只需要把『15』改成『14』就行。那么结果如何呢? 指令也是成功运行! 如果你不放心,你还可以重新测试一下『15』的值,然后你就会发现指令执行失败。 所以说,总结下来,红石比较器并不会导致红石信号衰减,也不会增强红石信号。借此原理,红石比较器的第一个重要用途就出来了: 保持信号强度(插图:91-6) 我们上面的讨论都仅仅基于a后侧输入口和o输出口,但红石比较器还有两个输入口:b左侧输入口和c右侧输入口。这两个输入口有什么用呢? 说到这两个输入口,就不得不提——红石比较器的模式。 红石比较器具有两种模式,可以通过观察靠近o输出口的那个红石火把的开关状态来判断此时比较器处于哪种模式: 比较模式——o输出口的红石火把关闭 作差模式——o输出口的红石火把开启 先来讲讲比较模式。当红石比较器处于比较模式时,b或c输入口输入的红石信号强度会和a输入口的红石信号强度作比较,如果b或c>a则o不输出,b或c≤a则o输出,也就是像下面这样子: ┊——0级 ┏o┓(插图:91-7) b△c? ┗a┛ ┊——14级 ┊——15级 ? ∵c=15,a=14 ∴c>a ∴o=0(不输出) —————————— ┊——14级 ┏o┓(插图:91-8) b△c┈┈┈?(这里有3格的红石线) ┗a┛ ┊——14级 ┊——15级 ? ∵c=13,a=14 ∴c<a ∴o=14(输出) 懂了吧?需要注意的是,如果b和c都有输入,那么游戏会先比较b和c,拿强度最大的和a比较: 空空┊——15级 空空┏o┓(插图:91-9) ?┈┈b△c┈┈┈? 空空┗a┛ 空空┊——15级 空空? ∵b=14,c=13 ∴b>c ∵a=15 ∴b<a ∴o=15(输出) 红石比较器的这个比较模式就是这样,同时这可以引出比较器第二个重要用途: 比较信号强度 当红石比较器靠近o输出口的红石火把开启时,红石比较器就进入了『作差模式』。作差模式的红石比较器会将a输入口的红石信号强度和b或c的红石信号强度相减,并将相减后的红石信号强度从o侧输出: 空空┊——1级 空空┏o┓(插图:91-10) ?┈┈b△c┈┈┈? 空空┗a┛ 空空┊——15级 空空? ∵b=14,c=13 ∴b>c ∵a=15 ∴o=a-b=15-14=1(输出) 不难发现,不管是在哪个模式,红石比较器都会先比较b和c输入口的信号强度,将最大的信号强度抽出来之后再操作a输入口的信号强度。 这个『作差模式』也就是这样,同时这也引出比较器第三个重要用途: 信号强度作差 那么比较器就这么讲完了吗? no,因为红石比较器还有第四个重要用途: 检测方块状态、方块实体和物品展示框 我们知道,红石比较器可以检测命令方块上一次的执行成功次数,然后将次数转化为红石信号强度进行输出。还可以检测许多容器,以及各种东西,然后输出特定的红石信号。对于隔壁红石来说,红石比较器常常用来检测容器内物品数量,甚至是通过不可堆叠和可堆叠的物品不断在漏斗内运动,然后使用红石比较器检测,来达到『随机数运算』的目的。只不过我们这边不需要用到这么复杂的东西(其实那也没多复杂),我们只需要能够用红石比较器检测命令方块的成功次数就行了: ┊——13级 ┏o┓(插图:91-11) b△c ┗a┛ ? 图例 ?······命令方块,上次成功运行次数为13次 上面是一个简易的例子——一个上次运行指令成功次数为13次的命令方块,通过比较器成功将成功次数转化为信号强度。 所以这就是本章的全部内容了。 附录:红石比较器历史 java 1.5——加入了红石比较器 1.6——能检测末地传送门框架和炼药锅了 1.8——能检测物品展示框和蛋糕了 1.9——比较器现在能够输入红石块的红石信号 1.14——能检测讲台和堆肥桶 1.15——能检测蜂巢和蜂箱 1.16——能检测重生锚 1.17——能检测幽匿感测体 携带\/基岩版 alpha0.14.0——加入了红石比较器 1.0.0——可检测末地传送门框架 1.0.5——可检测命令方块 1.1.0——可检测潜影贝 1.2.0——可检测唱片机 1.11.0——可检测烟熏炉、高炉、讲台和堆肥桶 ...... ...... ...... ...... 我们知道,红石信号等级上限为15,所以当命令方块的执行成功次数等于甚至大于15时,红石比较器就没作用了。 真的吗? 让我们来看一个例子: ┊——6级 ┏o┓(插图:91-12) b△c? ┗a┛ ? 图例 ?······命令方块,上次执行成功次数为21次 ?······红石块 这是一个处于『作差模式』的红石比较器,不难发现它的o=6,c=15。所以它的a为多少呢? a=o+c=21,也就是命令方块执行成功的次数 等等,不是说好红石信号等级上限为15的吗?怎么跑21去了? 严格来说,并不是说红石信号等级上限为15,而是『红石线的承载能力最大为15级』。所以如果我们不使用红石线,也就不会把命令方块的输出压到15级。 但是不使用红石线我们该怎样传导大于15级的红石信号呢? 用红石比较器。 由于篇幅限制,我们这边就不详细展开,接下来就请你自行研究去吧! 第九十二章 简单的红石脉冲 (此章节原为『红石比较器』,于2022年7月27日改为『简单的红石脉冲』) (此章节有用到本章说来插入图片,因此最好在起点中文网上阅读本章) 在java1.9版本中,mojang才为命令方块加入了『连锁』和『重复』这两个模式。因此在java1.9版本之前,命令方块只有『脉冲』这一种模式,也就是说命令方块在当时得依靠红石电路才能实现重复和连锁执行。虽然现在已经有了『重复』和『连锁』,但我们仍然应该要了解一下这个在java1.9版本前被广泛用于命令方块执行的东西: 红石脉冲(redstone pulse),俗称红石循环。 首先,让我们了解一下:什么是脉冲? 脉冲(pulse),又称脉波、脉冲波(pulse wave),指的是『一信号幅度的快速暂态变化,由基准值变为较高或较低的值,之后又快速的回到基准值』,用人话来说,就是一个东西,由一个形态快速变化成为了另一种形态,然后又快速回到了原本的形态。脉冲是有规律的,比如每1秒改变一个来回,或每0.05秒改变一次。在minecraft中,红石脉冲,也就是我们俗称的红石循环,就是指在短时间内,一段红石电路的信号快速地从无到有,再从有到无的过程。 红石脉冲有很多种类型,但最常见的无非也就这四种脉冲形式: 1普通脉冲(红石中继器脉冲)(插图92-1) 2单刻比较器减法脉冲(插图92-2) 3延迟减法脉冲(插图92-3) 4红石火把脉冲(插图92-4) 这四个脉冲各有各的优势,具体可以看下表: 脉冲名|速度|资源消耗|稳定度|简单程度 普通|+|++|+|+ 单刻比较器减法|+|+|-|+ 延迟减法|-|+|++|- 红石火把|+|+|--|++ 如果你要速度快,就采用『红石火把脉冲』或『单刻比较器减法脉冲』,如果你要稳定度好,就采用『延迟减法脉冲』,如果你要卡服,就采用......额,估计你不想你的服务器变得很卡吧? 说了这么多,那么这四个脉冲的速度究竟如何? 我们可以通过命令方块将三者在一定时间内的执行次数转化为分数,来与实际经过的游戏刻数进行对比。我们可以创建一个叫做timer的计分项,把分数放在上面之后将timer显示出来,接着让计算脉冲次数的和游戏刻消耗刻数的命令方法同时被激活,就像插图92-5一样。 然后我们就可以得到普通脉冲的执行数据: 游戏刻(gametick)——803 次数(times)——202 执行一次消耗游戏刻数(gametick\/times)——3.975≈4 每秒执行次数(s\/gametick·times)——5.031≈5 我们同样可以使用此方法,来测出另外两个的速度: --单刻比较器减法脉冲(插图92-6) 游戏刻(gametick)——809 次数(times)——203 执行一次消耗游戏刻数(gametick\/times)——3.985≈4 每秒执行次数(s\/gametick·times)——5.018≈5 --延迟减法脉冲(插图92-7) 游戏刻(gametick)——800 次数(times)——100 执行一次消耗游戏刻数(gametick\/times)——8 每秒执行次数(s\/gametick·times)——2.5 --红石火把脉冲(插图92-8) 游戏刻(gametick)——804 次数(times)——202 执行一次消耗游戏刻数(gametick\/times)——3.980≈4 每秒执行次数(s\/gametick·times)——5.025≈5 可见,这四个脉冲中三个的速度是每秒5次,唯一一个较慢的是每秒2.5次,这与『重复』命令方块每秒执行20次的速度相差甚远。但鉴于红石电路确实比较慢,所以这样的速度还能够理解。 但别忘了,本书是一个指令教程,所以我们用红石脉冲的目的并不是要弄红石电路,而是要让『脉冲』命令方块也能够实现重复执行的效果。而对于重复执行的命令方块来说,一个非常重要的特性就是:要容易控制 『重复』命令方块在『需要红石』的模式下,可以通过setblock或fill指令填充红石块或空气来实现控制的效果——这是一个十分流行且方便的控制方法,特别是在一些地图中,你应该也见过这种方法。而对于红石脉冲来讲,能不能用同样或类似的方法进行控制,就是一个非常重要的评判标准。 在上面的四种脉冲中,『普通脉冲』最不容易被控制(你可以研究一下怎么控制这东西),而剩下的三个都能够很好的被指令控制,其中红石火把的控制方式较为特殊——你需要放置的是红石粉而不是红石块(插图92-9)。 这就是本章的全部内容。 第九十三章 逻辑门 上 (此章节已于2022年7月27日重写) 我们都知道,execute的条件子命令可以是『条件成立即执行』,也可以是『条件不成立才执行』,但是testfor指令就不行了。 假设现在我们要在基岩版实现一个功能:如果以执行地点为中心,半径2米内没有任何的钻石掉落物,就在此处生成一个钻石。 至于怎样生成一个钻石,我们不用管(本章不讨论这个)。现在的问题是,怎样使得半径2米内没有任何钻石掉落物时才会激活用来生成钻石的命令方块呢? 答案很简单:制作一个非门。 非门是什么?在了解非门之前,我们得先了解一个东西:逻辑电路。 逻辑电路(logic circuit),简单来说,就是一个你往里面输入一些信号,它就会返回特定信号的电路。比如你往里面输入一个1,它就给你返回0;往里面输入一个0,它就给你返回1。 最基本的逻辑电路被称之为逻辑门(logic gate)。逻辑门其实并不是指一个门,它只是一个很简单的红石电路而已。逻辑门有很多种,每种逻辑门都拥有不同的作用。这一章,我们就来了解一些基本的逻辑门。 非门(not gate),又称之为『反相器』,是一种会反转输入信号的逻辑门。它的结构很简单,如下: ?█?(插图93-1) ?······未激活的拉杆(输入) █······任意完整方块 ?······开启的红石火把(输出) 为了方便,我们暂且把拉杆?这边的输入,叫做r,红石火把?这边的输出,叫做c。拉杆按下,r=1,否则r=0。红石火把开启,c=1,否则c=0。 现在的状态是拉杆没有拉下,红石火把开启,也就是: r=0 c=1 让我们改变一下拉杆的状态,拉下栏杆,然后你就会发现: 〇█ 〇······r拉下的拉杆 ······c关闭的红石火把 r=1 c=0 整理一下,我们就会发现,当我们给非门输入一个信号时,非门会把这个信号反转。体现在游戏中,就是你拉下拉杆,反倒关闭了红石火把;不拉下拉杆,反倒开启了红石火把。 说了这么多,那么这东西对我们有何帮助? 我们可以把『强度等级大于0的红石信号』视作1,『强度等级为0的红石信号』视为0。testfor指令执行成功后返回的执行成功次数总会是一个大于0的值,红石比较器转化后的强度等级也肯定大于0,也就是输出1。反之,testfor执行失败也就是输出0。看到这个1、0,你想到了什么? 二进制? 非门呐!反转信号啊!我们只需要在输出后面接上一个非门反转一下信号,不就可以实现『testfor执行成功输出0,失败输出1』了吗?让我们来试一试: ?□┠█??(插图93-2) □······重复型命令方块(testfor @e[r=2,name=钻石,type=item])\\\\检测半径二米内是否有钻石掉落物\\\\ ┠······r朝向东的红石比较器(比较模式) ?······c开启的红石火把 拉下拉杆,命令方块开始执行,但由于周围并没有钻石,指令执行失败,红石比较器没有输出信号,导致r输入一直为0,c输出自然就一直反转成1,红石火把便一直亮着。 让我们在旁边扔一颗钻石看看: ?〇□┠█(插图93-3) 你会发现红石火把熄灭了。 这是为什么?因为命令方块检测到了钻石,成功次数大于0,红石比较器将成功次数转化为红石信号后强度也就不等于0,同时转化后的红石信号也被输入到了非门中,也就是非门的r=1。红石火把接受到红石信号后就进入关闭状态,也就是非门的c=0。这样子,我们就成功地将testfor指令的执行结果反转,使得接下来的操作能够加以进行。 下面是完整版的『钻石生成装置』: ?〇a→?┠█!b→c→d→(插图93-4和93-5) 图例 〇······拉下的拉杆 a→······循环型命令方块,写有『testfor @e[r=2,name=钻石,type=item]』 ┠?······红石比较器 █······任意完整方块 !······红石火把(可能是亮也可能是不亮,故这边用感叹号) b→······脉冲型命令方块,写有『summon armor_stand diamond 84.47 -60.00 -91.30』 c→······连锁型命令方块,写有『receitem entity @e[name=diamond,type=armor_stand] slot.weapon.mainhand 0 diamond』 d→······连锁型命令方块,写有『kill @e[type=armor_stand,name=diamond]』 整个装置的运行流程如下: 如果半径2米内有钻石,就 →啥也不干 否则,就 →1生成一个盔甲架 →2让盔甲架拿着一颗钻石 →3然后杀死盔甲架,钻石就掉落了 非常简单是不是?这就是『非门』在指令中的主要用途。只不过随着execute指令的升级,非门也就慢慢地在指令圈中步入了历史。 ...... 所以逻辑门就这一种?肯定不是。 接下来我会快速介绍其他的一些门,这些门由于在指令中的使用频率会比非门少很多,我们就不详细讲解。如果你对红石感兴趣,我记得tis(trinity union,中国最厉害的生电服务器,你应该有听说过)他们的b站账号好像有在做红石教程,还有明月庄主好像也有教程。 与门(and gate),翻译成中文就是『当.....和.....都成立时,才会.......』。也就是说,与门是用来判断两个或两个以上的条件,当这些条件都成立时,输出c才会等于1。在编程语言中,与门也就是逻辑运算中的『且』,符号常常使用『&』或『&&』。 在minecraft中,与门有n多种做法,这边就列出一个最简单的一种: ?◆⊕(这里的拉杆为r1) 空┊!┈(插图93-6) ??◆⊕(这里的拉杆为r2) ┊······红石线,在这边红石线下面要有任意完整方块,使得它和旁边两个红石火把齐平 ?⊕······一个完整方块上面插着红石火把的结构 !······c输出用红石火把 ┈······红石线 ?◆······r输入用拉杆 空······空气,没有任何东西 与门有如下的特性: 当r1=0 r2=0时 c=0 当r1=1 r2=0时 c=0 当r1=0 r2=1时 c=0 当r1=1 r2=1时 c=1 也就是说,与门要全部输入都为1时,才会输出1。也就是要所有条件都为真(true)时,才会返回真(true)。 或门(or gate),翻译成中文就是『当......或......中有一个成立时,就......』。也就是说,或门同样也是用来判断两个或两个以上的条件。只不过和与门不一样的是,或门只需要部分条件成立就可以返回真,也就是输出c=1。在编程中,或门也就是逻辑运算中的『或』,符号常常用『|』或『||』来表示。 或门也有n多种做法,这边也是用最简单的一种: ◆┊(这里的拉杆为r1) 空┊┈(插图93-7) ◆┊(这里的拉杆为r2) ┊······红石线 ┈······c输出红石线 ◆······r输入用拉杆 空······空气,没有任何东西 或门有如下的特性: 当r1=0 r2=0时 c=0 当r1=1 r2=0时 c=1 当r1=0 r2=1时 c=1 当r1=1 r2=1时 c=1 也就是说,或门只要部分输入为1时,就会输出1。也就是当部分条件为真(true)时,就会返回真(true)。 这就是本章的全部内容,你会发现其实还是蛮简单的。如果你看不懂,那这边推荐你去找几个红石教程,本书讲红石确实是有点......比较不适合。 第九十四章 逻辑门 下 (本章已于2022年7月27~28日重写) 现在,我们已经知道了三道逻辑门: 非门(not gate)——反转信号 与门(and gate)——全部输入都为1才会输出1 或门(or gate)——部分输入为1就会输出1 这三道是最简单的逻辑门。在这一章,我们将会来看看复杂一点的五道门(其实也没多复杂)。 或非门(nor gate),简单来说,就是或门+非门。啥意思呢?我们来看一看或非门长什么样子: ◆┊(这里的拉杆为r1) 空┊!(插图94-1) ◆┊(这里的拉杆为r2) ┊······红石线 !······c输出用红石火把 ◆······r输入用拉杆 这就是或非门,让我们拿它和或门对比一下: ◆┊ 空┊┈ ◆┊ ┈······c输出红石线 你会发现或非门相比或门,仅仅就是把输出的红石线改成红石火把。但就是这么一个小小的改变,会有什么用? 我们来看看或非门的特性: 当r1=0 r2=0时 c=1 当r1=1 r2=0时 c=0 当r1=0 r2=1时 c=0 当r1=1 r2=1时 c=0 不难发现,对于或非门来说,只要有部分输入为1,就会输出0,必须要所有输入都为0才会输出1。等等,让我们回顾一下或门的特性: 『或门只要部分输入为1时,就会输出1。也就是当部分条件为真(true)时,就会返回真(true)』 这个特性......完全是相反的啊。 没错,或非门,其实就是在或门的基础上对或门的输出动了点手脚,加了个『非门』来反转信号,所以才被称作『或非门』,也因此具有和或门完全相反的特性。 同样的,既然有『或非门』,那自然就有『与非门』。 与非门(nand gate),具有和与门完全相反的特性。与门的特性是『要全部输入都为1时,才会输出1』,所以相反的与非门的特性就是『要全部输入都为1时,才会输出0』: 当r1=0 r2=0时 c=1 当r1=1 r2=0时 c=1 当r1=0 r2=1时 c=1 当r1=1 r2=1时 c=0 最简单的与非门,也就是在与门的基础上去掉c输出的红石火把,换成普通的红石粉(不是加上一个非门吗?): ?◆⊕(这里的拉杆为r1) 空┊┈(插图94-2) ??◆⊕(这里的拉杆为r2) ┊······红石线,在这边红石线下面要有任意完整方块,使得它和旁边两个红石火把齐平 ?⊕······一个完整方块上面插着红石火把的结构 ┈······c输出用红石线 ?◆······r输入用拉杆 异或门(xor gate),虽然带有『或门』字样,但其实它的特性和或门没有太大关系。异或门的结构有些复杂: ◆?⊕!─┈!(这里的拉杆为r1) 空┊┈!█|(插图94-3) ◆?⊕!─┈!(这里的拉杆为r2) ┊······红石线,在这边红石线下面要有任意完整方块,使得它和旁边两个红石火把齐平 ?⊕······一个完整方块上面插着红石火把的结构 ┈······红石线,在这边红石线下面要有任意完整方块,使得它高于地平线1米 ─······地平线上的红石线 |······地平线上的红石线,作为c输出点 !······红石火把 ?◆······r输入用拉杆 异或门具有如下特性: 当r1=0 r2=0时 c=0 当r1=1 r2=0时 c=1 当r1=0 r2=1时 c=1 当r1=1 r2=1时 c=0 也就是说,异或门必须在所有输入有不一致的情况下才会输出1,输入都一样反而会输出0。也就是当所有条件有不同时,才会返回真(true)。这就是为什么『异或门』开头为『异』,这个『异』就是指『不一样的输入』。 同或门(xnor gate)的特性和异或门完全相反,它的特性是这样的: 当r1=0 r2=0时 c=1 当r1=1 r2=0时 c=0 当r1=0 r2=1时 c=0 当r1=1 r2=1时 c=1 也就是说,同或门必须要所有输入一致才会输出1,输入不一致反而会输出0。这就是为什么这类逻辑门叫做『同或门』,其中的『同』字就代表『相同的输入』 同或门的结构其实就是在异或门的基础上套了个非门来反转输出: ◆?⊕!─┈!(这里的拉杆为r1) 空┊┈!█|┈!(插图94-4) ◆?⊕!─┈!(这里的拉杆为r2) 就因为同或门本质上是异或门+非门,所以同或门又被称为异或非门。 上面这些门都是较为简单并且特性较容易理解的逻辑门,所以本章就到这里了? 还有最后一个门:蕴含门(implies gate) 蕴含门听起来很高大上,但其实本质上只是在普通开开关关的两个输入中的一个加了个非门来反转信号: ◆?┈█!(这里的拉杆为r1) □□□┊┈c(插图94-5) □◆?┈┊(这里的拉杆为r2) ┊······地平线上的红石线 █······任意完整方块 ┈······地平线上的红石线 !······红石火把 ?◆······r输入用拉杆 c······输出 □······没有任何东西 蕴含门具有如下特性: 当r1=0 r2=0时 c=1 当r1=1 r2=0时 c=0 当r1=0 r2=1时 c=1 当r1=1 r2=1时 c=1 可见,蕴含门的逻辑较为特殊,它必须要在r1输入1且r2输入0的情况下才能输出0,也就是必须要第一个条件为真(true),第二个条件为假(false)才会返回假(false)。 这就是本章的全部内容,也就是五个逻辑门:或非门、与非门、异或门、同或门和蕴含门 其实逻辑门还有很多很多种造法,如果你对此感兴趣,可以在网上谷歌或百度一下(你就知道[滑稽])。 另外,其实像普通『r=1 c=1;r=0 c=0』的开就开,关就关的这种红石电路,其实也是逻辑门哦! 第九十五章 初识逻辑组 (本章原为『随机池-抽奖漏斗』,于2022年7月28日改为『初识逻辑组』) (最好在起点中文网上阅读本章) 在前面四章,我们了解了一些隔壁红石的知识点。但为什么我们要了解那些?因为我们要了解一个在命令圈中可以堪称元老级别的东西: 逻辑组 什么是逻辑组?在了解逻辑组是什么之前,我们还得把时间向前拨回到2012年10月25日。就在这一天,minecraft正式发布了一个对于指令圈有着重大影响的版本: minecraft pc 1.4.2版本(java版1.4.2)骇人更新正式版 此次版本中,虽然主打的是『凋零』以及和凋零相关的东西,但有一个重要的方块也在此版本出现。这个方块奠定了接下来几年中整个命令圈的基础。 这个方块是什么呢?命令方块! 在java1.4.2版本中加入的命令方块,和现在的命令方块有很大不同。当时的命令方块只能通过红石激活才能够运行指令,且激活一次只能运行一次,这就导致了当时的命令方块十分依赖于红石电路。因此,直到java1.9版本更新前,命令方块+红石电路基本上就是当时命令圈的标配(特别是在国内)。而这种使用红石电路将命令方块连起来的组合,就被玩家们称之为:逻辑组 只不过随着玩家们对游戏机制的深入了解,慢慢地就出现一些不怎么依赖红石电路的命令方块组合,这种方式最初由于较难理解其机制所以在国内使用不广。但随着java1.9版本的更新,加入了循环和连锁型命令方块,这种方式一下子就成为主流,并延续到现在。这种方式是什么呢?我们暂且不讲,但你大致应该知道是什么,因为我们已经接触过很多次了。 现在,逻辑组已经不仅仅只有『命令方块+红石电路』一种形式,还有纯命令方块的形式。为了方便区分,本书就将逻辑组按照其形式大致分为三类: 1红石逻辑组——单纯使用红石电路将命令方块组合起来的形式 2半红石逻辑组——有使用到红石电路,也有使用到其他方式来将命令方块组合起来的形式 3纯指令逻辑组——只是通过游戏机制或命令方块本身功能来将命令方块组合起来的形式 (ps:虽然指令圈内有逻辑组这个叫法,但只有本书是这么分类的) 这一章,我们主要来了解最古老的逻辑组:红石逻辑组 不管是什么种类的逻辑组,肯定都可以分为两部分: 核心——控制以及驱动整个逻辑组运行和更新的部分,按照类型可分为红石驱动和命令方块驱动 通路——整个逻辑组的附属部分 比如我们在第九十三章中用来实现生成钻石的那个命令方块组合,其实就是一个逻辑组,有核心和通路两个部分: ?〇a→?分界┠█!b→c→d→(插图95-1) (更准确的来说,是逻辑组中的半红石逻辑组) 这个逻辑组的左边部分『?〇a→?』由拉杆和一个重复型命令方块组成。拉杆用于控制整个逻辑组的运行,而重复型命令方块则在被拉杆激活的情况下不断运行以保障整个逻辑组的更新,所以这部分就是这整个逻辑组的核心。而右边部分『┠█!b→c→d→』是在左边部分的驱动下才会激活,是整个逻辑组的附属部分,所以叫做『通路』。 唉?运行和更新分别是指什么? 『运行』,也就是字面意思,运行命令方块和红石电路,执行指令嘛。 『更新』,指的是在一个处于运行状态的逻辑组中,使得逻辑组中的命令方块重新执行指令。 逻辑组按照运行次数还可以分为两种: 1脉冲型逻辑组——不存在更新的概念,每次激活就只运行一次 2重复型逻辑组——存在更新的概念,激活后会重复执行直到停止激活 这就是逻辑组的基本概念。 『红石逻辑组』可以说是最容易理解的逻辑组。那什么是『红石逻辑组』? 红石逻辑组,指的是全部通过红石电路,将许多命令方块组合在一起以实现特定功能的逻辑组。这种逻辑组非常依赖于红石电路的控制,所以具有如下的几个特点: 1容易控制 2执行速度较慢 3多采用红石逻辑,容易阅读 4占地面积大 5易受外界影响 6顶多每秒5次的执行速度 看起来这缺点很多啊,但这并不妨碍我们了解它,毕竟它可使最简单的逻辑组。 让我们来看一个例子: 红石 脉冲→a?b→c(插图95-2) ? 图例 ?······红石块 →······红石中继器 ?······红石比较器 这是一个java1.6.1版本的红石逻辑组(也是一个重复型逻辑组),还是非常典型的那种。不难发现,这个逻辑组的核心使用了『单刻比较器减法脉冲』来保证整个逻辑组的更新,而红石块就像拉杆一样控制着整个逻辑组的运行。在通路中,使用了红石比较器和中继器来保证执行顺序不会乱,并且有用到一点红石电路的逻辑在里面。那么这个逻辑组有什么用呢? 其指令如下: a······testfor @a[r=5] b······scoreboard yers add @a[r=5,c=1,x=20,y=4,z=200] count 1 c······give @a[score_count=5,r=5,x=20,y=4,z=200] 264 这个逻辑组会检测半径5格内是否有玩家存在,如果有就给这个玩家的count计分项加上1,增加过后如果这名玩家的count计分项分数不超过5,就给予这名玩家一个钻石。 也就是说,这可以使得每个经过这里的玩家都领到一些钻石,并且每人最多只能领取5颗。但由于红石电路的特性,导致理想很美好,实践起来可能有两个问题: 1如果玩家跑得太快,可能导致虽然检测到了,但是并没有给玩家钻石。 2如果保护没做好,有些玩家可能会不小心破坏掉红石脉冲,导致逻辑组停止更新 这就是红石逻辑组。如果你还不清楚,我们再来看一个例子: ?a→b→c(插图95-3) 图例 ?······木制压力板 →······红石中继器 这也是一个java1.6.1版本的红石逻辑组。但它的核心仅仅只有一个压力板来控制运行,并没有更新逻辑组的装置。所以这是一个脉冲型逻辑组,每次进入运行状态仅仅只会执行一次而已。 它的通路也是使用红石中继器来控制命令方块执行的顺序。那么这个逻辑组有什么用呢? 其指令如下: a······ysound mob.viger.yes @p[x=21,y=4,z=252,r=4]~1 ~1 ~ b······give @p[x=21,y=4,z=252,r=4] 32 c······tell @p[x=21,y=4,z=252,r=4]你获得了菜鸟的最爱! 这将会给处于压力板周围4格内的最近玩家(一般是踩着压力板的玩家)一个『枯萎的灌木』,并同时发出村民赞同的声音,告诉玩家『你获得了菜鸟的最爱!』。 这就是红石逻辑组的基础内容。如果你成功理解了本章的内容,那不妨发挥一下你的想象力,去尝试以红石逻辑组的形式做几个有点用的逻辑组出来,本章到此为止。 (注:在不同指令教程内『逻辑组』也有可能会有其他的叫法,但总之都是一个东西) (此章节有少部分概念和名词来自『指令方块进阶教程——模块(面向过程)』) 第九十六章 如何正确使用一个盔甲架 (此章节于2022年7月28日修改,但并未完全重写,因此语气会和其他章节有所不同) 盔甲架,能干什么? 可以穿上装备给人炫耀。 似乎就这个用途了。 真的是这样吗? 如果你认为盔甲架真的只有这个用途的话,那你就错了。 在建筑玩家眼里,盔甲架是一个很有用的装饰品;在红石玩家眼里,盔甲架是一个跳舞机;在指令玩家眼里,盔甲架是个很不错的服务器兼建筑工人;在pvp玩家眼里,盔甲架...... 今天,我们就来讨论: 如何正确使用一个盔甲架。 —————————————— 第一段——认识盔甲架 首先,让我们认识一下这位可怜的盔甲架兄。 盔甲架 命名空间id:armor_stand(je1.11更新前为armorstand) 是否会把牛顿气死:否 是否可自行移动:否 生命值:你只需要知道快速连续击打两下盔甲架就可以让其散架 合成:木棍|——木棍——|木棍 ———空空|——木棍——|空空 ———木棍|平滑石头台阶|木棍 是否可被命名:是 你可以在盔甲架上面放上盔甲,也可以在盔甲架的手上放上物品(如果你的盔甲架有手的话) 如果你把盔甲架破坏了,所有在其上的物品都会掉落。大部分附魔效果在盔甲架上无效,但也有例外: 1如果你用活塞将装备着附魔了冰霜行者的靴子的盔甲架推进水里,会把水冻成霜冰。 2如果你给盔甲架套上了附魔了深海探索者的盔甲,会减缓盔甲架被水流推动的速度。 3装备了具有荆棘附魔盔甲的盔甲架会在你攻击它时对你造成一些伤害[仅java版]。 盔甲架不会被仙人掌伤害,但是会被箭破坏。在基岩版,盔甲架会受到部分状态效果的影响。比如,盔甲架会受到瞬间伤害和凋零效果的影响,除此之外还会被熔岩、火或营火“杀死”(没错,盔甲架具有部分生物才有的特性)。 在基岩版,如果盔甲架上有物品或盔甲,该物品或盔甲会被视为系统自然生成的东西。所以当盔甲架因瞬间伤害或凋零的状态效果而导致“死亡”时,这些物品就会概率掉落(没错,而且这概率为8.5%!)。 因此请谨记——玩基岩版时,请不要将药水扔到盔甲架上,否则后果自负。 (似乎基岩版1.19.10中没这问题了唉) 估计很多人知道,盔甲架有很多种姿势。 那么到底有多少种呢? 截止2022年7月,一共13种。 前提是你得拥有一个有手臂的盔甲架(在java版需要通过指令生成,基岩版默认就有)。 ———————————— 第二段——盔甲架与建筑 作者在开头就提到了: 建筑大佬非常“钟爱”盔甲架。 那么到底是个怎么个“钟爱”法? 让我们来阅读一些建筑教程你就知道了: 只需要打开浏览器,然后找到一个minecraft建筑教程。 作者这边也找到了一篇教程,让我们看看开头: 最近,有一个外国小哥,在minec........ 等等,点错了,是这一篇: 『我的世界:盔甲架、旗帜、台阶几种简单的材料,搭配的成品很惊艳』(作者:十方游戏,于2020-3-29发布) 看标题就知道了,这是一个建筑教程,而且都写明了:材料有盔甲架。 那么为什么建筑大佬都“钟爱”盔甲架呢? 虽然作者不大会搞建筑(搞点小亭子还是可以的),但是在看了这么多建筑教程后,就算没玩过mc的人都可以总结出以下几点: 1.盔甲架不会偷偷溜走 2.盔甲架可以自由搭配 3.盔甲架不需要呼吸 盔甲架作为一个实体,被建筑大佬“钟爱”的第一点是不会溜走,这是很正常的——不然如果你拿头猪过来等你建筑建好之后发现猪竟然溜走了。 当然,做吊x台的除外(具体见『mc厂长——地狱中养鸡』)。 第二点可以自由搭配也很正常 那么第三点——盔甲架不需要呼吸。这点为什么这么重要呢? 如果你看过一些有关于盔甲架的建筑教程,就会发现: 盔甲架十有八九都被活塞给塞进方块里了。 或许我们可以把盔甲架改个名字了,就叫——史上最炫不管怎么被方块锤都不会坏盔甲架。 这就是为什么建筑大佬如此“钟爱”盔甲架的主要原因。 —————————— 第三段——盔甲架与红石 事实上,盔甲架在红石建造中比较少用,但为什么要提及呢? 因为盔甲架还有一点作用没提: 盔甲架被红石激活后会自动变换下一个造型。 所以使用盔甲架+红石,你就可以做出一个『跳舞机』。 问题来了,为什么盔甲架在红石电路中比较少用? 1.盔甲架是用木头做的,绝缘 2.盔甲架是个实体,且不会自己动 如果硬要说盔甲架有什么作用的话,或许可以当个小白鼠,来试运行一下你的红石装置。 —————————— 第四段——盔甲架与指令 那么盔甲架在指令中有什么用途呢? 答案是非常有用途。 让我们看一下盔甲架在指令中到底有什么用途: 1.服务器 当你游玩一些网络游戏时,就算你下线,游戏数据也会被保存下来。 那么保存数据的这个地方叫啥呢? 叫服务器。 服务器(server),是一种计算机,它一般会比你家的计算机运行得更快、存储容量更多、内存更大、价格也更贵(没个大几十万,就想买个服务器?额,还真行,现在一堆云都可以买,只不过钱给少的话就只能用点配置垃圾的服务器,然后开个土豆mc服务器)。 既然现实中有这种好东西,mc玩家们肯定也不会错过,于是他们无情地拿出了盔甲架,当作一个服务器用。 那么游戏中的盔甲架服务器(armor stand server,简称ass)有什么用呢? 可以用于存储计分板数据 如果你要存储数据,ass服务器是个不错的选择。 而且不需要交网费,你只需要交电费就可以了。 这个ass服务器的配置是怎么样的呢?让我们看一下: ass服务器运算速度=你的设备的cpu ass服务器的存储上限=你的硬盘剩余空间 ass服务器的价格=1个盔甲架 或许我们还需要再算上一点: ass服务器的维持费用<你的电费 正经一点。所以为什么盔甲架很适合用于储存计分板数据呢?有哪些优点? 1方便使用目标选择器来调用 2kill即可销毁 3可移动,十分灵活 4配合计分板可完成一些逻辑运算 5具有生物的一些特性 这些优点就是为什么盔甲架这么常用的主要原因。只不过盔甲架仍然具有一个缺点: 如果用太多,游戏mspt值会大幅下降,造成卡顿。这一点在1.18版本更新后的《我的世界:中国版》中体现得淋漓尽致。 2.建筑工人 盔甲架可以建筑? 是可以,只不过需要指令的帮忙。 盔甲架不仅兼ass服务器、跳舞机、装饰品、“人工智能”,还兼建筑工人。 那么怎么个用法呢? 如果你想要在mc画个圆(没错,你可以在mc画圆),你就需要盔甲架的帮助。 首先,你需要一个盔甲架来确定圆心(最好先给盔甲架命个名)。 然后,使用无限循环的命令方块填上: \/execute @e[type=armor_stand,name=圆心盔甲架名]~~~ tp @s ~~~~1 \\\\这条指令的意思是让盔甲架一直转圈\\\\ 接着请另外一个盔甲架过来,充当画笔。然后再摆两个无限循环命令方块: 其一:\/execute @e [type=armor_stand,name=圆心盔甲架名]~~~ tp @e[type=armor_stand,name=充当画笔那位盔甲架的名字]^^^圆半径 \\\\让『画笔』盔甲架一直处于圆心盔甲架的正前方x米处\\\\ 其二:\/execute @e[type=armor_stand,name=充当画笔那位盔甲架的名字]~~~ setblock ~~~<方块id> \\\\在画笔盔甲架的位置放置方块\\\\ 这样子,你就可以画出来一个圆。至于原理,其实很简单,结合我们之前学的内容你就可以搞懂了,因此这里不做解释。 你也可以不用盔甲架,拿个猪啊牛啊都可以,命名一下就好了。 但你要防止那些猪和牛被系统刷掉,以及它们窒息而死。 —————————— 第五段——结束语 没错,这一章就这么结束了。 相信你看完这一章后,一定会对你旁边那个戴着你的钻石套、披着你的钻石甲、套着你的钻石裤、穿着你的钻石靴、手拿钻石剑的盔甲架刮目相看。 本章到此为止。 第九十六章 番外 如何获得一个拥有手臂的盔甲架 (此章节已于2022年7月29日进行小幅度修改) 相信很多读者在看完上一章后,多多少少都会产生一个疑问——java版的盔甲架没有手臂啊。 如果你是一位纯基岩版玩家,那么恭喜你: 现在就可以跳过这一章 如果你对java版有手臂的盔甲架感到很好奇,那还不用着急退出。你只需要打开电脑,然后注册一个微软账号,花费亿些钱购买一个minecraft并下载,再配置一个java运行环境,最后只需要双击minecraft快捷图标,然后登陆——创建一个新的世界(建议超平坦),开启作弊,进入游戏。 接下来的事情很简单,你只需要获得一个命令方块就可以了。当然不获得也可以,只不过可能会有些麻烦。 万事具备,只欠指令。让我们正式开是今天的内容:在java版,如何获得一个拥有手臂的盔甲架。 ———————————— 既然是只欠指令,那么什么指令可以生成实体呢? 如果你并没有跳着看完这本书,就应该会知道有这么一条指令:\/summon。 再加上盔甲架的id:armor_stand,就可以得出生成盔甲架的指令: \/summon armor_stand ~~~ 但估计你也清楚,这样子生成出来的盔甲架也是没手,跟从创造背包里拿出来或工作台合成的一模一样。这个时候,我们就要使用万能的: nbt(数据标签) ——————————— 盔甲架有哪些特殊的nbt标签呢?答案是有下面这么几个: disabledslots(整数) invisible(布尔值) marker(布尔值) nobasete(布尔值) pose(复合标签) showarms(布尔值) small(布尔值) 让我们看一下这些标签分别是干什么用的: disabledslots——用于禁用盔甲架的某些部位,这里不详细讲解。 pose——用于调整盔甲架各个部位的角度,这里也不作讲解。 marker——如果指定这个标签的值为1,生成的盔甲架尺寸会被设置为0,实体碰撞箱也会变得几乎没有,小到你只能用\/kill来破坏 invisible——如果指定这个标签的值为1,在指令执行成功后如果你发现盔甲架似乎并没有生成,并不是出了bug,而是盔甲架处于隐形状态(浮空字就是用这东西做出来的)。 nobasete——如果指定这个标签的值为1,在执行指令之后如果你发现盔甲架似乎并没有底座,不是游戏出了问题,而是因为这个盔甲架的底座隐藏了起来。 showarms——如果指定这个标签的值为1,那么恭喜你:你的盔甲架有手臂了。 small——如果指定这个标签的值为1,那么你生成出来的盔甲架它不叫盔甲架,它叫小盔甲架,体型类似幼年的村民。 阅读了上面的『盔甲架数据标签使用指南』后,你应该知道如何获得一个拥有手臂的盔甲架了吧? 没错,就是: \/summon armor_stand ~~~{showarms:1} 附表:盔甲架简史 java版 1.8——加入了盔甲架 1.8.1——加入了marker标签 1.9——加入了handitems和armoritems两个标签以替换equipment标签 1.11——实体id从armorstand改为armor_stand 基岩版 1.2.0——加入了盔甲架 第九十六章 番外的番外 看,这个盔甲架高兴极了 (此章节于2022年7月29日进行大幅度更改) 众所周知,盔甲架具有13个姿势。 但如果严谨一些,上一句话的结尾可能还要再加上一个注意事项:[仅基岩版] 为什么要加上『仅基岩版』呢?是不是java版的盔甲架根本就不具有姿势呢? java版其实也有,只不过在java版中,盔甲架并没有预置的姿势, 那么问题来了,java版怎么让盔甲架更改动作? 首先让我们回顾一下第九十六章番外的内容: 『 disabledslots(整数) invisible(布尔值) marker(布尔值) nobasete(布尔值) pose(复合标签) showarms(布尔值) small(布尔值) 』 其中,更改姿势的秘密(这算是秘密吗?)就在这个复合标签里: pose{} 在pose复合标签内,具有下面几个标签: body——定义身体的角度 leftarm——定义左手的角度 rightarm——定义右手的角度 leftleg——定义左腿的角度 rightleg——定义右腿的角度 head——定义头部的角度 这些标签的值都是由三个浮点数组成的列表: [第一个浮点数a,第二个浮点数b,第三个浮点数c] a浮点数定义该标签对应部位的绕x轴旋转角度,b和c同理,分别是绕y轴和绕z轴的旋转角度。比如: \/summon minecraft:armor_stand ~~~{pose:{head:[90.0f,0.0f,0.0f]}} 这将会召唤出一个向南方低头的盔甲架。值得注意的是,这里的浮点数是『单精度浮点数』,因此必须在值的后面加上一个f,否则将会召唤出来的是一个普普通通的盔甲架。 这就是本章的全部内容。看,这个我随便弄出来的盔甲架高兴极了! 第九十七章 forceload-java版控制常加载区块 (此章节于2022年7月30日重写) 在『第二十八章:区块』中,我曾提到过java版和基岩版分别有一条指令用于控制常加载区块。我们在第三十二章具体了解了基岩版常加载区块指令的使用方法,但是java版的呢? 这一章,我们就来了解:java版控制常加载区块的指令 在minecraft java 1.13.1版本更新中,mojang为minecraft加入了一条全新的指令: \/forceload force,即『强制......』的意思;load,即『加载』的意思。因此,『force load』就是『强制加载』之意。这个\/forceload,也就是java版用来控制常加载区块的指令。 \/forceload 作用:强制使区块不断加载 存在版本:java1.13.1-今 需要权限等级:java-2 需要作弊:是 格式: \/forceload add <起点方块坐标>[终点方块坐标] \\\\使得与框选范围有重叠的区块不断强制加载\\\\ \/forceload remove <起点方块坐标>[终点方块坐标] \\\\使得与框选范围有重叠的区块不再强制加载\\\\ \/forceload remove all \\\\使得当前纬度所有区块不再强制加载\\\\ \/forceload query [位置:方块坐标] \\\\查询所有正在加载的区块,或检查指定位置所在的区块是否正在被强制加载\\\\ 虽然forceload和基岩版的tickingarea都是用来控制常加载区块的,但两者却有那么一点点不一样:前者是直接控制区块,后者是控制由区块组成的常加载区域。 啥意思呢? 当你在使用\/tickingarea控制常加载区块时,实际上是在控制由一个或多个常加载区块组成的不同的常加载区域。这就是为什么当你使用\/tickingarea添加常加载区块时,要指定名称的原因,因为你实际上是在通过框选得到的区块来创建一个常加载区域,然后游戏会让这个常加载区域内的所有区块不断加载。 而\/forceload就没有『常加载区域』这个概念,因为当你使用forceload控制常加载区块时,还真的就是直接控制到区块本身,而不是控制由区块组成的区域。这就是为什么你使用forceload添加常加载区块时不需要指定名称的原因。 比如: \/forceload add ~~ 假设你此时在主世界的(17,42,18)这个位置,那么这条指令将会使得你所在的区块不断强制加载,并返回以下数据: 已将minecraft:overworld中的区块[1,1]标记为强制加载 需要注意的是,由于区块不考虑y轴,所以你在使用forceload添加常加载区块时不需要指定y坐标,只需要指定x和z坐标即可。 上面这条信息中,区块[1,1]是什么意思? [1,1]在这边并不是一个普通的坐标,而是区块坐标。区块坐标本质上和普通的mc坐标没啥差别,唯二的两个差别无非以下两个: 1区块坐标的单位长度为16格,也就是1区块边长 2区块坐标的x、z坐标均为整数(y坐标其实也是,只不过如果算上y坐标的话就变成区段坐标了) 也就是说,上面的区块[1,1],指的就是(16,?,16)这个坐标位置所处的区块。 现在,让我们尝试一下取消这个区块的强制加载: \/forceload remove ~~ 如果你的位置在刚才都没有发生改变,那么这条指令将会使得你所在的区块,也就是区块[1,1]解除常加载: 已将minecraft:overworld中的区块[1,1]解除强制加载 但如果你已经跑到了其他区块,那么运行上述指令只会返回: 没有强制加载的区块被移除 那么我们该怎么找到被强制加载的区块呢?这时候就需要用到query子命令来查询: \/forceload query 运行上述指令,不出意外的话,游戏应该会返回以下信息: 在minecraft:overworld内找到一个强制加载的区块:[1,1] 然后呢?怎么移除?运行『\/forceload remove 1 1』吗? nonono,上面已经说过了,[1,1]这个是区块坐标,你需要将它的x、z坐标均乘以16才能将其转化为能够被我们使用的坐标: \/forceload remove 16 16 这样子才行嘛。当然,如果你觉得这很麻烦,也可以通过运行: \/forceload remove all 来取消当前纬度的所有常加载区块。 这就是本章的全部内容。对了,query的可选参数『位置』也是填写普通的坐标,并不是填写区块坐标哦! 附录:\/forceload历史 java 1.13.1——加入了\/chunk,并重命名成了\/forceload 1.14.4——现在\/forceload的权限要求为2 ...... ...... ...... (我很好奇,这些营销号是什么眼光,竟然仅仅只看上了这个章节。然后现在一堆什么csdn、爱代码爱编程等营销号都跟风转发。只不过,它们转发的是旧版的章节,并不是本书第一次大修过后的章节。所以如果你之前有看过那些营销号的文章,请注意,那并不是他们自己写的,而是转发了以前本章节的内容) 第九十八章 触发器-简单的注册\/登录系统 上 (本章已于2022年7月31日重写) 现在,我们已经了解了n多条指令,并学会了搭建红石逻辑组,但我们似乎并没有拿所学的知识来做点什么有趣的东西。在此前的章节中,最多最多,我们也就用了几个命令方块来实现诸如生成钻石之类的小功能,谈不上有多厉害。 所以在接下来的内容中,我们将会用指令在minecraft java1.19版本中尝试做出一个有趣的具有实际功能的东西,那到底这个东西是什么呢? 在『第五十一章 whitelist-白名单』这一个章节,我提到了在minecraft java的离线服务器中,单纯使用白名单并不保险。而在给出的三个解决方法中,第二条写到: 『不要使用原版的服务端,采用第三方可以装插件的服务端或在原版服务端的基础上装forge再加上spongeforge(海绵端),并给服务器装上适宜的登录插件,让玩家进入服务器还需输入一次密码进行二次验证』 现在有很多minecraft java服务器就是这么干。这些服务器往往会开两个甚至更多的mc服务器——一个主服,另一个是专门用来登录的登录服。当玩家想要进入他们的服务器时,往往并不会直接进入到主服,而是先进入到登录服进行登录,登录成功后玩家才能进入到主服(例子有easecation服务器,你在服务器退出登录后就会来到它的登录服)。对于某些没钱的服务器来说,虽然开不了登录服,但也会装一些登录插件,让玩家在登录之后才能进行全部的操作。 但是不管怎样,以上的效果都是要在安装第三方服务端,并安装服务器插件(甚至可能还要配置数据库)之后才能做到。那在原版中,我们能否通过指令来实现以上效果呢? 如果仅仅说是做出一个『注册\/登录』的效果来说,在minecraft java版中当然是可以的,而且也很容易做出来。让我们来试一试。 要做出『注册\/登录』系统,首先我们要清楚: 什么是注册和登录? oxfordnguages词典对『注册』一词的定义如下: 『特指电子计算机某网络的用户向该网络输入用户名、密码等,以取得对该网络的使用许可』 结合我们平常注册账号的常识,不难得出,注册和登录的流程是这样的: 用户向服务器发送注册\/登录请求→服务器让用户填写用户名和密码等信息→用户填写完后,将信息发送至服务器→服务器检查信息→服务器根据检查的结果,判断是否允许用户进行下一步操作 现在,我们要在minecraft中做出『注册\/登录』的效果,本质上其实就是要实现上面的流程。而为了实现上面的流程,我们就要研究一下如何把上面的流程转化到minecraft中。 我们可以做一个房间,设置出生点就在这个房间里面,然后放置一个按钮在墙上,并告诉玩家需要点击这个按钮来注册\/登录。玩家点击这个按钮后,就会激活相应的逻辑组运行指令,此时就可以输入用户名和密码进行注册或登录,命令方块也会获取到玩家填写的内容,并进行一番操作,最后告诉玩家是否成功,如果成功则将他传送到外面。 前半段很简单,我们可以很容易做出来一个里面放着一个按钮的房间(插图98-1)。难点其实在后半段,有两个难点要解决: 1怎么让玩家输入用户名和密码,并将这些信息存储到哪里? 2怎么检测玩家输入的内容是否符合要求? 先来看第一个问题。 让玩家输入用户名和密码,首先就是要有一个能够让玩家输入文字的地方。在minecraft中,哪里可以输入文字呢? 多得去了!聊天框、书与笔、铁砧、命令方块......重点在于,我们是否可以正确获取到玩家输入的文字,并将其储存起来? 先来看看书与笔。我们可以检测书与笔的nbt,然后将获取到的信息储存在....... 书与笔的内容肯定不只是数字,所以我们不能将信息储存在计分板中,只能将信息储存到某个nbt标签中。然而,一方面我们还没有正式学习nbt,另一方面我们也不知道储存在哪里,储存完后又该如何获取如何修改,因此采用书与笔作为输入框的方法对于现在的我们来说,不可取。 既然书与笔不可取,那么铁砧、命令方块等一大堆东西就都不行了。额,所以现在,我们应该怎么获取、从哪获取到玩家的输入内容并将其储存起来呢? 或许我们应该换个角度思考:我们可以将玩家输入的内容存储到哪里? 对于现在的我们来说,计分板是个不错的选择。等等,那么我们是否可以开放一个计分项让玩家自由修改,然后我们再从中获取计分项的值呢? 好主意!但问题来了,要修改计分项的话,玩家就得有2级权限(java版),但就算是个傻子也不会给刚进服的玩家2级权限吧?况且,\/op和\/deop可不能在命令方块中运行。 那是否有没有一种方法,能够让没有权限的玩家也能够修改特定计分项的值呢? 还真有!那就是: 触发器(trigger) 在『第四十一章 objectives——管理一个计分项』中,我们曾经了解到trigger准则计分项所具有的特性: 『触发器,类似于dummy,但所有玩家均可修改自己的trigger型计分项』 也就是说,我们可以创建一个trigger准则的计分项,然后指示玩家去修改自己在这个计分项上的分数,进而达到『玩家输入,我们也能检测到并储存』的效果。 那我们到底该怎样正确使用触发器呢? 让我们先创建一个trigger准则的计分项: \/scoreboard objectives add password trigger 这将会创建一个叫做『password』的trigger准则计分项,我们将会使用它来储存玩家的密码。 然后呢,怎么让玩家能够修改? 你应该知道,让玩家使用\/scoreboard yers set 去修改自己的trigger类计分项的分数是不现实的,因为scoreboard必须要2级权限才能使用。因此,mojang专门为触发器加入了一条指令: \/trigger 作用:修改执行者自己的trigger计分项上的分数 存在版本:java1.8-今 需要权限等级:java-0 需要作弊:否 格式: \/trigger <允许的trigger计分项> \\\\使执行者自己在指定计分项上的分数+1\\\\ \/trigger <允许的trigger计分项>(add|set)<值> \\\\设置执行者自己在指定计分项上的分数\\\\ 举个例子: \/trigger password set 1 如果password是个已被启用的trigger计分项,那么运行上述指令将会修改执行者自己在password计分项上的分数为1。 等等,『已被启用』是个啥意思?trigger计分项要被修改还得先启用? 没错,mojang虽然给了我们触发器,但是这个触发器并不是随时随地都能让没权限的玩家自由修改的。要让玩家能够使用触发器,首先你需要使用scoreboard yers enable命令来为指定玩家启用触发器: \/scoreboard yers enable <目标> 比如: \/scoreboard yers enable @s password 就可以让我们自己能够修改一次password。注意啊!不是无限修改,而是只能修改一次! 就算你为指定玩家启用了触发器,但只要那批玩家使用trigger指令修改了一次,那么触发器就会自动关闭,直到我们再次为他们开启触发器。也就是说,如果你这样运行指令,将会得到如下结果: \/scoreboard yers enable @s password 已为xxx启用了触发器[password] \/trigger password set 1 已触发[passoword](数值已设为1) \/trigger password set 1 你尚无法触发这个记分项 总而言之:要让玩家修改触发器,得先打开触发器,然后玩家就能够修改一次,修改完后触发器自动关闭,直到下一次被打开。 懂了吧?现在我们回来看看上面的第一个问题,你是否已经想到了解决办法? 没错,就是: 先创建一个储存密码用的password的触发器计分项(这步我们上面已经完成了)。当玩家按下按钮时,为其打开该触发器,并指示玩家通过\/trigger指令修改该触发器的值,同时不断检测玩家是否已经输入。当检测到玩家输入时,对玩家输入的内容进行检查,如果符合条件则通过检测,否则重新打开触发器,让玩家重新输入。 这已经非常符合最终的注册和登录流程了。但是我们仍然要解决两个问题: 1如何检测玩家是否输入了密码? 2到底密码要符合怎样的条件才可以通过检测? (唉作者,用户名呢?用户名怎么办?) (其实不需要用户名,玩家名称完全可以当成用户名来使用) 对于第一个问题,我们有两个解决办法: 1不断检测触发器的值是否改变,也就是通过execute的条件子命令判断 这个方法最简单,但是有些问题:万一玩家输入的是默认值该怎么办? 2不断尝试为指定玩家打开触发器,并将成功次数存储到另一个计分项上 这个方法也很简单,只要计分项的值不等于0,就代表着打开触发器成功,也就代表玩家已经输入过了。这同时也能解决『万一玩家输入的是默认值』的问题。 因此,我们不妨采用第二个解决办法,创建一个专门的计分项来记录触发器是否打开成功: \/scoreboard objectives add is_typed dummy 然后在等待玩家输入密码的过程中,不断重复执行: \/execute as 玩家 store sess score @s is_typed run scoreboard yers enable @s password 随后检测就可以了。 第二个问题就更简单了,因为这个问题没有标准答案,我们也不会在这章讨论这个问题。 现在,我们成功解决了输入的问题,整个『注册\/登录』系统的最大难关已被拔除。在下一章,我们将会尝试搭建一个简陋的beta版本,来检测一下我们的想法是否可行。 第九十九章 初识模块-简单的注册\/登录系统 下 (此章节已于2022年7月31日重写) 在上一章,我们解决了一个世纪难题:输入。这一章,我们将会尝试实现『注册』这个功能。 我们先理一下这个系统到底是怎样的: 1有一个password触发器,存储着玩家的密码,注册时玩家要填写的字段 2有一个is_typed计分项,用来检测玩家是否填写了密码 3玩家按下按钮后,为玩家打开password触发器,并指示玩家通过\/trigger指令填写密码。玩家填写密码后,检测玩家的密码是否符合要求,如果符合则通过检测并传送走玩家,如果不符合则返回错误信息,并再次为玩家打开触发器指示玩家填写。 理清楚之后,我们就可以开始动工了。我们将会采用前几章刚了解的『红石逻辑组』作为基础来建设这个系统。先搭建一个简单的结构: ◎墙→a→b (插图99-1) ◎······按钮 →······红石中继器 首先,既然要『玩家按下按钮后,为玩家打开password触发器』,那么第一个命令方块a就应该填写: scoreboard yers enable @p password \\\\为最近的玩家开启它的password计分项\\\\ 命令方块b用来实现『指示玩家通过\/trigger指令填写密码』,因此填写: tellraw @p {“text“:“请运行指令\\“\/trigger password set <密码>\\“输入账户密码来注册“,“color“:“yellow“} \\\\告诉最近的玩家『请运行指令“\/trigger password set <密码>“输入账户密码来注册』\\\\ 然后呢?我们需要一个一直处于运行状态的红石逻辑组来不断检测玩家是否已经输入密码,所以我们要在旁边搭建一个红石脉冲并配上一些命令方块: 脉冲→c→d→e (插图99-2) c:execute as @p store sess score @s is_typed run scoreboard yers enable @s password \\\\检测玩家是否输入密码\\\\ d:tellraw @p[scores={is_typed=1}]{“text“:“注册成功,请记好你的密码哦!“,“color“:“green“} \\\\给已输入密码的玩家发送成功提示\\\\ e:execute as @p[scores={is_typed=1}] run tp @s 13 -60 10 180 0 \\\\把注册成功的玩家传送走\\\\ 这样子,我们的beta1.0注册登录系统就做好了!让我们来试一试: *按下按钮* 请运行指令“\/trigger password set <密码>“输入账户密码来注册 *输入指令:\/trigger password set * 已触发[password](数值已设置为) 注册成功,请记好你的密码哦! *被传送走* 运作得十分棒!但是,如果你再次尝试使用trigger指令的话...... *输入指令:\/trigger password set * 已触发[password](数值已设置为) 注册成功,请记好你的密码哦! ?我不是注册过了吗? 没错,这个beta1.0的系统漏洞百出,它起码有这几个问题: 1已注册的玩家可再注册 2password一直可以被修改 3可能无法很好应对多玩家情况 4系统运作较慢 5对于后续扩展出『登录』功能不友好 为了解决这些问题,我们可以采用tag标签对玩家进行标记。那么我们会用到哪些tag标签呢? ?对于注册中的玩家,需要registering标签 ?对于已经注册的玩家,需要registered标签 ?对于处于登录中的玩家,需要logging_in标签 ?对于已经登录的玩家,需要logged_in标签 其中,register是注册的意思,log in是登录的意思。 我们需要在玩家刚刚开始注册\/登录时给玩家添加上registering或logging_in标签以防止选择到那些已经登录和注册的人,给那些注册成功的玩家添加上registered标签和logged_in标签并移除掉registering标签,给那些登录成功的玩家添加上logged_in标签并移除掉logging_in。在后面,我们还会使用更多的标签来完善整个系统的运作。 另外,我们还需要关闭成功注册玩家的password触发器以防止注册了还能再修改password,还需要在每次红石逻辑组结束运行时重置每名玩家的is_typed的分数值。前者我们可以通过execute以玩家为执行者运行一遍trigger password add 0来实现,后者可以通过加上写有『scoreboard yers set @a is_typed 0』的命令方块来实现。 让我们在系统中加入标签进行筛选,并加入上面的指令,看一看是否能够解决一些问题: ◎墙→a→b→c(插图:99-3) 脉冲→d→e→f→g→h→i→j a:execute positioned ~~~-4 run tag @a[distance=..3,tag=!registered,tag=!logged_in] add registering \\\\给未登录且未注册的玩家添加registering标签\\\\ b:scoreboard yers enable @a[tag=registering] password c:tellraw @a[tag=registering]{“text“:“请运行指令\\“\/trigger password set <密码>\\“输入账户密码来注册“,“color“:“yellow“} d:execute as @a[tag=registering] store sess score @s is_typed run scoreboard yers enable @s password e:execute as @a[tag=registering,scores={is_typed=1}] run tag @s add registered \\\\给成功注册的玩家添加registered标签\\\\ f:tellraw @a[tag=registering,scores={is_typed=1}]{“text“:“注册成功,请记好你的密码哦!“,“color“:“green“} g:execute as @a[tag=registering,scores={is_typed=1}] run trigger password add 0 \\\\将成功注册玩家的password触发器使用一遍以关闭\\\\ h:execute as @a[tag=registering,scores={is_typed=1}] run tp @s 13 -60 10 180 0 i:execute as @a[tag=registering,scores={is_typed=1}] run tag @s remove registering j:scoreboard yers set @a is_typed 0 \\\\重置is_typed\\\\ 现在,我们的『注册\/登录系统』beta2.0测试版出来了!让我们测试一下: n个『已将xxx的[is_typed]分数设为0』 *按下按钮* 已为xxx添加了标签''registering'' 请运行指令“\/trigger password set <密码>“输入账户密码来注册 n个『已将xxx的[is_typed]分数设为0』 *输入密码* 已触发[password](数值已设置为) 已为xxx启用了触发器[password] 已移除xxx的标签''registering'' n个『已将xxx的[is_typed]分数设为0』 ...... 出bug了,还是个很严重的bug。 不要慌张,让我们来排查一下到底是什么问题。 仔细阅读上面的日志,你会发现: 由于红石逻辑组的特性,在过长的逻辑组中,执行顺序会难以把控,然后就出现了上面的问题。 那该怎么办? 改用『纯指令逻辑组』。 『纯指令逻辑组』,其实是目前最常见的逻辑组。它有一个更加专业的说法:模块。在本书中,它也被称之为『命令块链』。 我们其实已经见过很多次『纯指令逻辑组』了,它其实就是由一个脉冲或循环型命令方块+一大串连锁型命令方块组成的。比如下面的这串命令方块: a→b→c→d→(插图:99-4) (为了方便,下面我都会称这东西为『模块』) 在这边,箭头代表着命令方块的朝向,a为循环型,bcd均为连锁。这些命令方块的朝向使得它们环环相扣。 循环型命令方块a是整个模块的核心,它负责整个模块的更新。如果a还是『始终活动』,那么a还具有维持整个模块运行的功能。我们从a是循环型这一点也不难看出,这个逻辑组还是个重复型逻辑组。 连锁型命令方块bcd是整个模块的通路。相比红石逻辑组通过红石元件来控制执行顺序,模块通路的执行顺序更加直观也不容易出乱子——因为它是通过命令方块的朝向来决定执行顺序。这也就是为什么在上面的模块中,执行顺序是从左到右的原因。 模块的难点在于对通路的理解,更确切地说是对『连锁型命令方块』运作机制的理解。还记得我们在第二章提到的内容吗?让我们回顾一下: 『青得一批的那个是链(又叫做连锁),作用是你叫它动一下(接入红石信号),它不会动。它只会在收到执行信号时,将该执行信号立马传递给下一个它指向的链命令方块,然后再根据当前条件判断是否要执行。听起来似乎有点复杂?举个例子: e→f→g→h→ 其中,e是未被激活的脉冲命令块,fgh三个命令方块都是已被激活且无条件限制的链命令块。当e激活时,efgh将会同时执行指令,因为e激活时向f发出了执行信号,f收到后也向g发出了信号,g也向h发出了信号,三个链命令方块也都没有条件限制。』 现在,让我们仔细研究一下上面的efgh为何会这样子执行。为了搞清楚为何这样子,我们就得研究一个东西: 执行信号 可以肯定的是,游戏本身并没有『执行信号』这东西,但为了方便大家理解,我就根据命令方块的性质总结出来了『执行信号』这个东西。那么这东西有什么特别的呢? 脉冲型和循环型命令方块,在被激活的同时不仅仅会尝试运行指令,还会产生执行信号并尝试将其传递给它所朝向的连锁型命令方块。 连锁型命令方块不管是无条件还是条件限制、需要红石还是始终活动、有被激活还是没被激活,只要它收到了执行信号,那么它就一定会尝试将该信号传递给它所朝向的下一个连锁型命令方块,当然它在传递的同时也会根据当前条件决定是否要运行指令。 举个简单的例子: 甲→乙→丙→丁→(插图:99-5) 甲:脉冲型,需要红石,无条件,没有写指令 乙:连锁型,没有写指令 丙:连锁型,没有写指令 丁:连锁型,需要红石,无条件,写有\/setblock ~~1 ~ diamond_block 当我们同时激活甲和丁时,尽管甲乙丙都会因为没有填写指令而执行失败,但丁却因为收到了由甲产生并经过乙丙传递的执行信号,加上本身已被激活且没有条件限制,就执行了指令,在上面放置了一个钻石块。 这就是执行信号。但连锁型命令方块并不一定会在接收到执行信号后立马就执行指令,它还会看一下情况: 1如果自身未被激活 →不会运行指令,仅仅会传递执行信号 2如果自身已被激活 →1.如果没有条件限制 →→尝试运行指令,然后再传递执行信号 →→否则不会运行指令,仅仅会传递执行信号 →2.如果有条件限制 →→如果正后方的命令方块上一次执行指令成功 →→→尝试运行指令,然后再传递执行信号 →→→否则不会运行指令,仅仅会传递执行信号 举个例子: 戊→己→庚→(插图:99-6) 戊:脉冲、不受制约、需要红石,填有『setblock ~~1 ~ minecraft:diamond_block』 己:连锁、条件制约、始终活动,填有『say yes』 庚:连锁、不受制约、始终活动,填有『say no』 当我们第一次激活『戊』命令方块时,戊就会在上方放一个钻石块,己由于戊执行成功,就会发送『yes』的消息,庚由于不受制约所以肯定会发出『no』的消息,最终三个命令方块都运行了指令。 当我们第二次激活『戊』命令方块时,由于戊上方已经有钻石块了,所以指令执行失败。己由于戊执行失败,自己也不会执行。最终只有戊和庚执行并且只有庚执行成功。 如果你能看懂并理解上面的内容,那么恭喜你,你已经基本上掌握了连锁型命令方块的运作机制,模块本身最难以理解的点已被攻破。现在让我们回到注册\/登录系统上,尝试以模块的形式替代原有的红石逻辑组: ◎墙a→b→c→(插图:99-7) d→e→f→g→h→i→j→ a[脉][无][红]——execute positioned ~~~-3 run tag @a[distance=..3,tag=!registered,tag=!logged_in] add registering b[链][无][始]——同替代前 c[链][无][始]——同替代前 d[重][无][红] e[链][无][始] f[链][无][始] g[链][无][始] h[链][无][始] i[链][无][始] j[链][无][始] 现在,我们系统的beta3.0版本出来了,让我们测试一下bug有无解决: *按下按钮* 已为xxx添加了标签''registering'' 请运行指令“\/trigger password set <密码>“输入账户密码来注册 n个『已将xxx的[is_typed]分数设为0』 *输入密码* 已触发[password](数值已设置为) 已为xxx启用了触发器[password] 已为xxx添加了标签''registered'' 注册成功,请记好你的密码哦! 已触发[password](数值已增加0) 已将xxx传送到 13.,-60.000000, 10. 已移除xxx的标签''registering'' n个『已将xxx的[is_typed]分数设为0』 解决了!!! 现在,我们已经完成了这个系统的大半部分,接下来我们将会尝试完成『检测玩家的密码是否符合要求,如果符合则通过检测并传送走玩家,如果不符合则返回错误信息,并再次为玩家打开触发器指示玩家填写』这个部分。 其实这个部分相当简单。比如我们想要玩家不能设定密码为0,就可以这么干: 在d命令方块后面插入两个新的命令方块,写入以下内容 execute as @a[tag=registering,scores={is_typed=1}] unless score @s password matches 0 run tag @s add correct_input \\\\为密码不是0的玩家添加标签correct_input(正确输入)\\\\ execute as @a[tag=registering,scores={is_typed=1}] if score @s password matches 0 run tag @s add error_input \\\\为密码是0的玩家添加标签error_input(错误输入)\\\\ 修改e、f、g、h、i命令方块的内容为 execute as @a[tag=correct_input,tag=registering] run tag @s add registered tellraw @a[tag=correct_input,tag=registering]{“text“:“注册成功,请记好你的密码哦!“,“color“:“green“} execute as @a[tag=correct_input,tag=registering] run trigger password add 0 execute as @a[tag=correct_input,tag=registering] run tp @s 13 -60 10 180 0 execute as @a[tag=correct_input,tag=registering] run tag @s remove registering 在i后新增命令方块3个,内容为 execute as @a[tag=correct_input,tag=registered] run tag @s remove correct_input execute as @a[tag=registering,tag=error_input] run tellraw @s {“text“:“请不要将0作为你的密码,请重新输入“,“color“:“red“} execute as @a[tag=registering,tag=error_input] run tag @s remove error_input 让我们测试一下: ...... *输入密码* 已触发[password](数值已设置为0) 已为xxx启用了触发器[password] 已为xxx添加了标签''error_input'' 请不要将0作为你的密码,请重新输入 已移除xxx的标签''error_input'' *再次输入密码* 已触发[password](数值已设置为1) 已为xxx启用了触发器[password] 已为xxx添加了标签''correct_input'' 已为xxx添加了标签''registered'' 注册成功,请记好你的密码哦! 已触发[password](数值已增加0) 已将xxx传送到 13.,-60.000000, 10. 已移除xxx的标签''registering'' 已移除xxx的标签''correct_input'' ok,完美运行,这就是系统的beta4.0版本。 只不过由于篇幅限制,我们就讲到这里。接下来对于『登录』功能甚至『登出』功能的实现,请你自己独立完成。这边有几个要求和提示: 1登录模块和注册模块要分开,但其实两者的原理都差不多 2创建一个新的触发器enter_password,用于登录密码的输入 3优化模块的运行,使得玩家在按下按钮后才会调用登录和注册模块,并在没有处于登录\/注册中的玩家后停止模块运行(提示:setblock或fill红石块) 4创建一个新的触发器,已登录的玩家可以修改此触发器到一个特定的值来退出登录 5新玩家进来后必须要出生在注册\/登录房里 6未追踪玩家的分数无法被比较。所以如果你拿未追踪玩家的分数来比较,由于没有分数,所以游戏总会返回false(假) 你可以加qq群或通过作家的话中的网盘链接获取到我做的完整『注册\/登录系统』的存档(minecraft java1.19版本,非网易版)。 本章到此为止。 第一百章 开启nbt时代(来,开杯香槟酒庆祝一下,100章了) (此章节已于2022年8月4日重写) 首先,在正文开始前,我们先庆祝一下本书写到了100章。 好巧不巧,第一百章正好正式开讲nbt。 但估计nbt也要讲100章了....... 当然,开杯香槟酒庆祝一下那是必须的。 没香槟酒怎么办?拿雪碧也可以。 那么,正文开始! —————————————— 在第五十四章中,我们初步了解了nbt(named binary tag),搞懂了snbt的格式。在接下来的章节中,我们将会依次了解物品、实体和方块的nbt,并更加深入地研究nbt的数据类型,以及搞懂如何将nbt用于指令的方方面面。 在本卷的前面部分,我们会重点了解物品的nbt。虽然nbt仅仅只能在java版中使用,但我们也会接触到一些基岩版的类似内容(如物品的json组件),所以基岩版玩家也可以来看看。 本卷的后面部分将会开始接触实体的nbt,实体nbt的相关内容起码要到第十七卷才能结束。但其实你并不需要每章都看,因为作者都是根据minecraft wiki上列出的那些『通用标签』来选择讲哪些nbt的,对于一些冷门的通用标签你大可不必了解,等到真正需要时再看也不迟。 第十二卷我们会暂时休息一下,然后开始深入学习json文本。第十五卷我们还会详细了解f3调试界面(所以这跟指令有何关系)。也就是说,尽管接下来有很多章节,但其实nbt的内容的占比不到一半。 等等,什么是『通用标签』? 在minecraft中,难免会有一些类似的生物,比如僵尸和尸壳。但它们又是不同的实体。如果它们的nbt标签也不同的话,那么写指令的以及做开发的都很头疼。『通用标签』因此诞生。 『通用标签』,正如其名,是指多个不同种类的东西带有的相同名称和功能的标签。比如『实体通用标签』,就是指几乎每个实体都具有的标签。通用标签可以方便mojang官方和模组开发者开发新的东西,也可以方便cber们(cber,mand blocker,玩命令方块的玩家,也就是指令玩家)使用nbt。我们会在接下来的章节中,详细了解各种『通用标签』。 虽然通用标签有很多种,但常用的也不过以下几个: 1物品通用标签(最好把这个标签背下来) 2实体通用标签 3方块实体通用标签 4生物通用标签 只要你能搞懂这四个通用标签,那你的nbt基本上就过关了。至于什么『箭通用标签』、『火球通用标签』等等冷门的标签,除非你需要使用到它们,否则一般不需要学习它们的用法。这就是为什么你可以跳着看的原因。 在正式开始nbt的学习过程前,我们得详细了解minecraft java的一次重大更新: java1.13扁平化 我们都知道,java1.13版本是『水域更新』,加入了珊瑚、溺尸等等新奇的东西。但java1.13也是一个分水岭,在此次更新中,miencraft java的基础源代码被大量重写,导致许多模组被迫停留在1.12.2版本,甚至弃坑。但这次重写也促进了新时代模组的产生,涌现出了基于原版的数据包、fabric、rift等新时代的模组,使得minecraft进入了一个全新的时代。 在指令方面,java1.13的更新内容也不容忽视。java1.13扁平化对许多指令以及指令的相关内容作出了很多重大改变,比如先前我们遇到的execute指令,就是一个鲜明的例子。 在扁平化中,首当其冲的就是数据值的消失。由于数据值的消失,很多id都被拆分了。比如『灰色床』,它在1.12.2是被统一到『床』(bed)里,作为数据值为7的床。而在扁平化后,『床』被拆分,『灰色床』就有了自己的id:gray_bed。当然,还有少数id被合并。比如java1.12.2的『水』(water)和『流动的水』(flowing_water),合并之后(1.13)统一成了:水(water)。 也有些并没有被拆分或者是合并,而是被『重命名』了,比如『甘蔗』在java1.12.2的id是『reeds』,到了1.13就变成了『sugar_cane』;岩浆块在1.12.2叫做『magma』,扁平化之后就变成了『magma_block』。 不只是这些方块、物品的id被改变,实体的id也被改变了,只不过比较少,可以全列出来: 经验球 1.12.2——xp_orb 1.13——experience_orb 附魔之瓶 1.12.2——xp_bottle 1.13——experience_bottle 末影之眼 1.12.2——eye_of_ender_signal 1.13——eye_of_ender 末影水晶 1.12.2——ender_crystal 1.13——end_crystal 烟花火箭 1.12.2——fireworks_rocket 1.13——firework_rocket 命令方块矿车 1.12.2——mandblock_minecart 1.13——mand_block_minecart 雪傀儡 1.12.2——snowman 1.13——snow_golem 铁傀儡 1.12.2——viger_golem 1.13——iron_golem 唤魔者尖牙 1.12.2——evocation_fangs 1.13——evoker_fangs 唤魔者 1.12.2——evocation_iger 1.13——evoker 卫道士 1.12.2——vindication_iger 1.13——vindicator 幻术师 1.12.2——illusion_iger 1.13——illusioner 除了方块、实体、物品的命名空间id被改变,就连生物群系(这是几乎都被重命名了)、粒子、声音、画、名字(这个并不是指id,而是它们显示出来的名字)很多也被改变,具体情况可以自己上minecraft wiki查阅。其中,画、粒子的id也有了命名空间(minecraft:)。而方块状态这个我们还不怎么了解的东西也做了大量的改变。 记分板准则也有了命名空间,比如『击杀生物』这个准则: 1.12——stat.killentity.<实体id> 1.13——minecraft.killed:namespace.<实体id> 并且在1.13更新后,这个准则和另外一个准则(被实体击杀)所选择的实体其范围也不止能用刷怪蛋生成的实体,而是所有实体都可以用。 nbt也有很大的改变,比如『物品通用标签』中的damage标签,在1.12.2中的作用是存储物品的数据值,而到了1.13就被调到了tag标签下,成为了『物品的损坏值』(具体见第一百零三章)。 命令的改变,大部分就是类似于\/give的改变——数据值、方块状态和nbt与命名空间id参数的合并。受到这种影响的指令有: \/clear \/clone \/fill \/give \/receitem \/setblock 还有一些其他的小改变,本书就不列出了,想看的话就到minecraft wiki上自己去查『扁平化』。 夕阳的光辉消失在远方的地平线上,银白色的方月自东方缓缓升起。一位钻套玩家疾跑在桦木林中,他手上的火把如同暗淡的星光点亮了前进的道路。朝前望去,在无数灰白方柱的掩映下,一座由橡木制成的房子缓缓出现,房子上的火把似乎有着无穷的魔力,吸引着这名玩家不断靠近。 咔嚓一声,房子的橡木门被打开。房子内也有一位戴着钻套的玩家。听到房门打开的声音,他的目光从工作台上移开,看向了那位从遥远的主城跑过来的玩家——张三。 那位叫做张三的玩家率先发了一条消息:『嘿李四,你知道吗,我搞到了腐竹箱子里的一把级锋利的下界合金剑!我们要发财了!』 『???』 『你怎么偷的?那里可是有出生点保护的啊!』 『额这个其实并不是我偷的,是一个管理员偷的。告诉你,这把剑可是我花了100多大洋弄到的』 『那还等什么啊?赶紧趁服务器没其他人去刷啊!』 『你确定这把剑附魔的是级的锋利?』一位叫做王五的玩家插嘴到。 『千真万确』张三把那把剑丢了出来。 『?』 『老子昨天听别人说这附魔等级最高也才啊?这腐竹是开挂了吗?!』 『好像腐竹开挂挺正常的啊』李四打趣到。 『等等』张三不知为何突然紧张了起来,捡起了那把剑。 『刚刚腐竹在群里说要上线!赶紧撤!』 →张三退出了游戏 →王五退出了游戏 →李四推出了游戏 ...... →[超级管理]一只可爱的猫加入了游戏 →[服主]某某不是女装大佬加入了游戏 第一百零一章 简单了解数组 (此章节已于2022年8月4日重写,原章节为『java1.13扁平化』) 在开始了解物品的nbt标签之前,我们得先填一点第五十四章的坑:数组 数组(array),在nbt中指的是由特定类型的整型数组合在一起的列表。和一般列表不一样的是,数组必须要在列表的开头标注上『类型字母』来声明该数组的数据类型。数组一共有三种,分别是字节型数组(byte array)、整型数组(int array)和长整型数组(long array)。这一章,我们就简单了解一下最常遇到的『整形数组』。 整形数组,也就是由普通的整形数(int整型)组合成为的数组,数组开头要标上大写字母『i』来声明该数组是整形数组。你目前并不需要了解int整型是个什么东西,你只需要知道int整型是整型数据类型中的一种即可。我们在接下来还会碰见更多的数据类型,但其实无非也就是不同的整型和浮点数,我们会在第十四卷中具体了解到关于数据类型的详细内容。 让我们来看看整型数组到底长什么样: [i;10,2,42,1] 这是一个简单的整型数组。其中,『i』即英文单词『integer』的缩写,用来声明这是一个整型数组。英文半角分号『;』用来将声明部分和内容部分分开。 如果去掉『i;』呢?会变成什么? [10,2,42,1] 如上,就变成了『由「int整型数」组成的列表』。 不难发现,上面的『整型数组』和『由「int整型数」组成的列表』相比,仅仅多了一个『i;』用来声明这是一个整型数组,其他地方则完全一样。 数组还是很简单的,对吧?这就是这一章的全部内容。 第一百零二章 物品组件 (此章节已于2022年8月5日重写) 在第八章中,我们了解了\/give指令的用法。让我们回顾一下: --java1.13以下 \/give <玩家:目标选择器><物品id:字符串>[物品数量:整数][物品数据值:整数][nbt标签] --java1.13及以上 \/give <玩家:目标选择器><物品英文id:字符串>[物品数量:整数] --基岩版 \/give <玩家:目标选择器><物品id:字符串>[物品数量:整数][物品数据值:整数][附加标签:json] 值得注意的是,在基岩版的格式中,『物品数据值』参数后面竟然还有一个『附加标签』参数。等等,附加『标签』?难不成基岩版的指令中也可以使用nbt? 你想多了,这当然不是nbt,而是一个基岩版独有的非常类似于nbt但实际上是json的东西: 物品组件(item ponents) 物品组件这东西,正如其名,是可以用在物品上的json组件。由于使用的是json而不是snbt的语法,因此物品组件的格式和java版的nbt有些许不同。那到底有哪些物品组件?我们又该如何使用它们呢? 截止基岩版1.19.10版本,一共有4个物品组件: can_ce_on can_destroy item_lock keep_on_death 虽然这里的json不是json文本,但这些组件和普通的原始json文本组件的用法仍然一样。 物品组件的值必须是一个json对象,也就是像下面这样: {“物品组件“:{}} 而具体这个json对象内能够填写哪些东西,得看使用的是什么物品组件。 can_ce_on和can_destroy这两个物品组件十分类似,它们俩也是最年长的物品组件,你或许早已知道它们的用途: can_ce_on——指定该『方块类物品』可以被放置于哪些方块上方 can_destroy——指定该物品可以破坏哪些方块 这两个物品组件适用于冒险模式。你应该知道,在基岩版中,处于冒险模式的玩家无法破坏或放置任何方块。因此,妥善运用上述组件,就可以指定玩家能够破坏或放置哪些方块,使得玩家的自由度更高,也能够弄出更多的玩法。 那么它们到底该怎么使用呢? 你需要在这两个组件的值,也就是它们的json对象中,使用blocks组件(值类型为字符串列表),指定具体可以破坏或放置的方块。比如: \/give @s diamond_shovel 1 0 {“can_destroy“:{“blocks“:[“minecraft:dirt“,“minecraft:grass“]}} 这将会给你一把在冒险模式中能够破坏泥土和草方块的钻石铲铲。can_ce_on组件的使用方法同理: \/give @s diamond_block 1 0 {“can_ce_on“:{“blocks“:[“minecraft:dirt“,“minecraft:grass“]}} 这将会给你一块在冒险模式中能够放置于泥土和草方块上方的钻石块。 可惜的是,这两个组件似乎无法指定具体的方块数据值以及方块状态,这就限制了这两个组件的使用范围。 item_lock和keep_on_death这两个组件是基岩版于1.16.100版本中新添加的。由于它们俩比较新,所以目前知道的人并不多。但这两个的用处可不是一般的大: item_lock——将物品锁定于背包或指定栏位中,使得物品无法被移除、丢弃或用于合成。 keep_on_death——使得物品在死亡后不会掉落 keep_on_death组件的使用方法非常简单,你甚至不需要指定它的json对象内到底该填写什么,只需要放一个空空如也的json对象作为它的值即可: \/give @s diamond_shovel 1 0 {“minecraft:keep_on_death“:{}} 这将会给你一把不会因死亡而掉落的钻石铲(不受游戏规则『死亡不掉落』是否开启的影响),可以说十分简单且有用。你应该注意到了,物品组件也具有命名空间。 item_lock组件可以将物品锁定在玩家的物品栏中。它具有两个模式,需要使用mode组件在它的json对象中指定: lock_in_inventory——锁定在玩家的背包中,玩家可以在背包中调整物品的位置,但物品无法被移除、丢弃或用于合成。 lock_in_slot——锁定在玩家的栏位中,玩家不可在背包中调整物品的位置,物品也无法被移除、丢弃或用于合成。 举个例子: \/give @s apple 64 0 {“item_lock“:{“mode“:“lock_in_inventory“}} 这将会给你自己一组苹果。你虽然可以使用它并调整它的位置,但这些苹果无法被销毁、丢弃或用于合成,你也无法将这些苹果放到其他容器中。但如果你死亡的话,这些苹果仍然会掉落。另外,这些苹果也可以通过指令移除掉。 再来一个例子: \/receitem entity @a slot.hotbar 0 book 1 0 {“item_lock“:{“mode“:“lock_in_slot“}} 这将会把所有玩家的快捷栏第一格的物品替换为一本书,并且这本书会被锁定在这个栏位中。当然,这本书也会在死亡时掉落。 有趣的是,虽然你握不住空气,但是下面这条指令却可以强制让你『握住空气』: \/receitem entity @s slot.hotbar 0 air 1 0 {“item_lock“:{“mode“:“lock_in_slot“}} 当你使用上述指令后,看起来你的快捷栏第一格只是变空了而已,也可以把其他物品放在这一格。但如果你把主手切换到这一格然后去尝试挖或使用方块,你就会发现:你破坏不了也使用不了方块了!破坏方块后方块会迅速恢复原来的状态,就像服务器保护一样!只不过,当你把其他东西放到这一格时,使用这一格来挖或破坏方块便不会出现什么问题。 上面这些就是基岩版的json物品组件的全部内容。既然基岩版有类似nbt的物品组件,那么java版有没有类似这些功能的nbt标签呢? 答案当然是有的,只不过是部分有,也就是: can_ce_on → canceon can_destroy → candestroy 在java版中,canceon和candestroy这两个nbt标签的用途和基岩版的对应物品组件一模一样,唯一的区别就在于使用的方法。java版的这两个标签的数据类型都是『文本列表』,而不是一个复合标签。列表内就直接填写能够放置或破坏的方块id,比如: \/give @s diamond_shovel{candestroy:[“minecraft:dirt“,“minecraft:grass_block“]} 1 这条指令是刚才的『\/give @s diamond_shovel 1 0 {“can_destroy“:{“blocks“:[“minecraft:dirt“,“minecraft:grass“]}}』在java1.13及以上版本的写法,它们具有同样的作用:给你一把在冒险模式中能够破坏泥土和草方块的钻石铲铲。canceon的用法和candestroy标签一样,这里就不多讲解了。 这就是本章的全部内容。 附录1:物品组件历史 携带版\/基岩版 ?——加入了can_ce_on和can_destroy两个物品组件,但没有用 1.1.0——can_ce_on和can_destroy两个物品组件现在可正常使用 1.16.100——加入了item_lock和keep_on_death两个物品组件 附录2:类似物品组件的nbt标签历史 java版 1.8——加入了canceon和candestroy标签 第一百零三章 《关于工具耐久的这档事》 (此章节已于2022年8月5日进行大修改) 众所周知,在基岩版和java1.13以下版本,如果你更改一个有耐久物品的数据值,改成1以上,你就会发现,数值越大,这个物品的耐久度就越低。当数据值大于物品耐久度的时候,游戏仍然会更改成功,只不过这个物品有个缺点: 这是一次性物品(当然对于有些地图作者来说是优点) 比如下面的指令: \/give @s diamond_shovel 1 9999 由于9999的数据值已经远超钻石锹的1561点耐久度,因此上面的指令将会给你一把一用就坏的钻石锹。 在基岩版和java1.13以下版本,你可以通过上述方法快速获取到具有指定耐久值的工具。但是,对于java1.13及以上版本,我们该怎么办? mojang给出的答案是:用nbt 而mojang给出的nbt标签是『damage』,是一个值为int整型的标签,中文翻译为『损坏值』。这东西的用法和我们拿数据值来指定物品耐久度一样,比如: \/give @s diamond_sword{damage:20} 1 你就会获得一个损坏值为20的钻石剑,也就是耐久度为1541点的钻石剑(满值为1561点)。 这就是在java1.13及以上版本获得具有指定耐久度物品的方法。但如果我们要的是『永远也不会损坏』的效果,那该怎么办?用\/receitem或\/item一直修改damage为0吗? 不需要这么麻烦,因为mojang也给出了一个nbt标签:unbreakable(无法破坏的) unbreakable标签的值是一个布尔值,默认情况下它为0,也就是false(关闭)。你可以手动改为1变成true(开启)。当unbreakable标签的值为1,也就是true(开启)时,该物品就会具有一个『无法损坏』的属性,也就达成了我们想要的效果。 举个例子: \/give @s diamond_sword 1 0 {unbreakable:1}——java1.13以下版本 \/give @s diamond_sword{unbreakable:1} 1 ——java1.13及以上版本 这样子,你就拥有一个耐久度为∞的钻石剑了! 附录:本章相关历史 java版 1.7.2——加入了unbreakable标签 1.13——移除了数据值,damage标签被移到物品tag标签下 (把unbreakable和damage都写上会发生什么?) 第一百零四章 物品的显示属性 在minecraft中,每个物品都有自己的名字。比如『minecraft:diamond』这个物品就叫做『钻石』、『minecraft:air』就叫做空气......但物品的名字并不是一直都不变的,我们可以通过铁砧来更改物品的显示名称,比如把『钻石』更改为『煤炭』,把『空气』更改为『黄金』....... 但用铁砧改名字十分麻烦,那有没有一种方法,能够通过指令更改物品的名称呢? 在java版中,是有的。这种方法就是:指定或修改物品的显示属性。 什么是物品的显示属性?我们知道,一个物品有自己的名称,自己的图标(方块类物品除外),还有这个物品显示出来的信息。比如这把钻石剑,它就具有如下的显示属性: [图标]——钻石剑的图标,是一把蓝色的剑 钻石剑——钻石剑的名称 在主手时:——这个和下面这些都是该物品的信息 7 攻击伤害 1.6 攻击速度 minecraft:diamond_sword ——这个和下面的是打开高级提示框后才会显示的信息 nbt : 1个标签 (配图:104-1) 那我们该如何指定或修改物品的显示属性呢?很简单,通过物品的nbt标签来修改。 物品的disy标签,是一个复合标签,用来自定义该物品的显示属性。大部分物品并没有这个标签,因为对于游戏来说显示属性弄个默认值就好。 disy这个复合标签内,有两到三个标签: color(int整形)——这个标签仅仅对皮革盔甲才有用,它可以指定皮革盔甲是什么颜色。 name(文本)——该标签对任何物品都管用,它可以自定义该物品的名称。这东西必须要使用json文本。在java1.13以下版本中,可直接使用普通文本,但无法使用json文本。 lore(文本列表)——该标签对任何物品都管用,它可以自定义该物品的描述。列表中的文本必须要使用json文本。在java1.14以下版本中,可直接使用普通文本,但无法使用json文本 看起来还是很简单的,让我们试试能不能获得一个名为『这不是钻石』的钻石: \/give @s minecraft:diamond 1 0 {disy:{name:“这不是钻石“}} \\\\适用于java1.8~1.12.2\\\\ \/give @s minecraft:diamond{disy:{name:“\\“这不是钻石\\““}} \\\\适用于java1.13~今\\\\ \/give @s minecraft:diamond{disy:{name:''“这不是钻石“''}} \\\\适用于java1.14~今\\\\ 上面给出了三条指令。这三条指令所适用的版本范围各有所不同,但功能都是一样的:会给你一个名叫『这不是钻石』的钻石。 值得注意的是,对于java1.13及以上版本来说,name的值虽然说『必须是一个json文本』,但如果你尝试下面的指令: \/give @s minecraft:diamond{disy:{name:“111“}} 这将会给你一个名叫『111』的钻石。注意!『111』在这并未使用json文本,但游戏成功识别了它。这是怎么一回事? 其实不止name标签,在minecraft java版中任意必须使用json文本的地方,都具有类似的特性:当使用阿拉伯数字时,可不使用json文本。不信?试一试下面的指令: \/tellraw @s 你会发现你正常收到了这条消息,游戏并未报错。对了,基岩版则没有类似的特性,所以如果你在基岩版运行上面的指令还是会报错的。 回到正题。既然name标签我们会使用了,那lore标签呢? 也一样简单。比如我们要获取一个描述为『never gonna give you up』的13号唱片,只需要: \/give @s record_13 1 0 {disy:{lore:[“never gonna give you up“]}} \\\\适用于java1.8~1.12.2\\\\ \/give @s music_disc_13{disy:{lore:[“never gonna give you up“]}} \\\\适用于java1.13.x\\\\ \/give @s music_disc_13{disy:{lore:[“\\“never gonna give you up\\““]}} \\\\适用于java1.14~今\\\\ \/give @s music_disc_13{disy:{lore:[''“never gonna give you up“'']}} \\\\适用于java1.14~今\\\\ 获取到后,你会发现物品的描述并不是白色的文字,而是紫色的文字。在java1.14以下版本中,由于lore无法使用json文本,自然也就改不了颜色(除非你有办法在nbt中使用§)。但在java1.14及以上版本中,我们就可以试一试改下颜色: \/give @s music_disc_13{disy:{lore:[''{“text“:“never gonna give you up“,“color“:“red“}'']}} 上述指令将会给你一个带有红色『never gonna give you up』描述的物品。 lore作为一个文本列表,我们这么用还是太屈才了。让我们试试把『never gonna give you up』拆开: {lore:[''“never“'',''“gonna“'',''“give“'',''“you“'',''“up“'']} \\\\这是java1.14及以上版本的例子\\\\ 然后放入指令中运行,你就会发现你获得了一个带有如下描述的13号唱片: never gonna give you up 如你所见,lore列表内的每一个元素,都代表了一行文本。 这就是name和lore的使用方法。那color标签,又该如何使用? color标签的数据类型是int整形,也就是一个整数,并不是一个字符串。也就是说,我们并不能使用red、yellow之类的颜色id,也不能使用rgb或16进制颜色代码。那这个color到底该怎么使用? color的值要填写的是颜色值。这个颜色值本质上是基于颜色的rgb算出来的,具体公式如下: rx+gx256+bx1 r······red红色值,0~255 g······green绿色值,0~255 b······blue蓝色值,0~255 举个例子。标准黄色的rgb值为(255,255,0),我们就可以通过上述公式算出标准黄色的颜色值为: 255x+255x256= 让我们试一试这个值正不正确: \/give @s minecraft:leather_helmet 1 0 {disy:{color:}} \\\\java1.13之前\\\\ \/give @s minecraft:leather_helmet{disy:{color:}} \\\\java1.13及之后\\\\ 然后我们就获得了一个颜色为(#ffff00)的黄色皮革帽子。其中,#ffff00正是标准黄色的16进制颜色代码。 到这里,物品的显示属性,也就是disy标签就讲完了,但这不代表本章到此结束。 如果我们不想要显示某些东西该怎么办? mojang给了我们一个标签可以用来指定隐藏物品的哪些信息: hidegs(int整形) hidegs的使用方式和上面的color有异曲同工之妙。和color类似,hidegs的值是『信息值』(这名字随便取的),你需要通过以下信息加上具体情况来计算出它的值: 1——附魔信息,对应enchantments(ench)标签 2——属性修饰符信息,对应attributemodifiers标签 4——无法损坏信息,对应unbreakable标签 8——能够破坏的方块信息,对应candestroy标签 16——能够放在哪些方块上的信息,对应canceon标签 32——其他大部分信息(包括药水效果、魔咒信息[storedenchantments标签]、成书的版本和作者信息[generation和author标签]、烟花火箭的信息[explosion和fireworks标签]、地图的信息) 64——[1.16.2版本新增]皮革盔甲的颜色信息,对应上面的color标签 比如我们要隐藏皮革盔甲的颜色信息,只需要: \/give @s minecraft:leather_helmet{disy:{color:},hidegs:64} \\\\java1.16.2及之后\\\\ 然后你就会惊喜的发现,相比之前的那个黄色帽子,这个新的黄色帽子没有了颜色信息。 但如果我们还要隐藏掉附魔信息该怎么办? 很简单,加起来就可以了: \/give @s minecraft:leather_helmet{disy:{color:},enchantments:[{id:“protection“,lvl:255}],hidegs:65} \\\\java1.16.2及之后\\\\ 运行上述指令,你将会获得一个附魔有保护255级的黄色帽子,但这个帽子并不会显示自己的颜色和附魔信息,除非你用的版本低于1.16.2才会显示出来颜色信息。 不难发现,上面的hidegs标签的值为65,是将64和1相加得到的。同理,如果你把上面表格的所有信息对应的值都加起来,得到的127这个值就代表所有信息,将其作为hidegs的值就可以隐藏掉物品的所有信息。 这就是本章的全部内容。 附录1:本章相关历史 java 1.8——加入了hidegs标签和能够用来自定义显示属性的disy标签。 1.13——name标签现在必须使用json文本。原本用来翻译用的lame标签被合并到了name标签里。 1.14——lore标签现在必须使用json文本。 1.16.2——为皮革盔甲的颜色信息加入了64(g 64)信息值。 附录2:lame标签用法 和json文本的trante组件一样,lame标签在java1.13以下版本用于物品名称的翻译。比如: \/give @s diamond 1 0 {disy:{lame:“item.pass.name“}} \\\\java1.13以下版本\\\\ 这将会给你一个叫做『指南针』的钻石。如果你把游戏切换成英文,那么这个钻石的名称也会变成『pass』(指南针的英文)。在上面的指令中,『item.pass.name』是『指南针』这个物品名称的本地化键名。 虽然我们还未接触到java版的trante组件,但其实java版json的trante组件和基岩版的trante组件的用法几乎一模一样。 ...... ...... ...... ...... 张三又一次大老远的从主城跑了回来。 『嘿,李四,你看这个附了魔的苹果!』 李四很好奇:『附了什么魔?』 『你自己看』 张三把苹果丢给了李四。 『这没写啊?』 张三从李四的手中拿回苹果,然后说道:『我也不知道。但据某位管理说,谁被这个苹果打到,就会获得无限时长的最高等级幸运效果。』 『真的?快打我一下试试!』 『那你待会也要打我一下,不能够你自己独享』 『ok,毕竟咱俩可是兄弟』 『准备好了吗?3——2——1——』 李四被张三用苹果杀死了 基岩版玩家的32767级锋利的苹果 众所周知,在基岩版,由于指令中无法使用nbt,所以你不可能使用指令来获得一个附魔有级锋利的苹果。 但这就代表着基岩版没有nbt吗? 并不是这样的。nbt双版本都有,但只有java版拥有能够用于指令上的snbt。虽然基岩版无法通过指令来修改nbt,但我们可以借助外部软件的帮助对nbt进行修改。 基岩版有很多能够修改nbt的软件,其中在国内最出名的就是blocktopograph(中文直译:区块地形图)。当然,也有其他能够修改基岩版nbt的软件,你可以前往浏览器搜一搜。 这是一个android软件,它可以控制并修改一个minecraft基岩版的存档,当然首先你得有一个minecraft基岩版(网易国际都行)。那怎么使用这款软件弄出一个级锋利的苹果呢? 很简单,打开这个软件,找到苹果所在的存档并进入。 进入世界后,映入眼帘的是主世界的地图,你可以右滑滑出菜单(有点反人类)。 地图是以区块作为单位的,也就是16x16。上面有标注玩家位置和实体位置。我们可以点击区块进行操作,比如传送玩家,修改区块数据等等。 接下来重点就来了:怎么修改苹果? 在修改苹果之前,作者建议你先拿个钻石剑练练手: 第一步——把钻石剑附上锋利(方便修改) 第二步——把钻石剑放在一个箱子里,最好确定一下这个区块就只有这个箱子。 第三步——打开blocktopograph,找到那个箱子的区块 第四步——点击区块,选择『打开该区块中方块实体的nbt』 第五步——找到id为chest的方块,也就是箱子 第六步——点击items文件夹 第七步——找到id为276的物品,276是钻石剑的数字id 第八步——找到tag下的ench文件夹(是不是很熟悉了?) 第九步——找到id为9的附魔属性(锋利),接着把lvl修改成 第十步——打开minecraft,然后你就可以....... 我们最终要改的是苹果,但苹果可不能通过正常途径附魔啊! 很简单:把钻石剑的nbt复制到苹果上面不就完事了? 请你在箱子里放入一个苹果,最好不要堆叠。然后再次打开软件,找到id为260的物品,260是苹果的数字id。 重点来了!复制钻石剑的tag标签! 然后怎么粘贴呢? 长按苹果的标签(items的子标签),在打开的选项中选择『粘贴(作为该标签的子标签)』。 什么?你选择了『粘贴(覆盖该标签)』?没按保存吧? 按了??? 恭喜你,你损失掉了一个苹果(还不快把这个标签删除掉!)。 在粘贴完成后,点击右下方的保存按钮,退出nbt编辑器,打开minecaft。 恭喜你,你成功获得了一个附魔了级锋利的苹果! 你可以在github上找到该软件,至于github是什么,怎么使用,你自己去b站上找教程。另外,此软件似乎已经停更,最后更新的版本是2020年7月22日的v1.9.4版本(它的官网也挂掉了),因此可能无法适用于最新的minecraft版本。 ...... ...... ...... ...... ...... 像这样子在基岩版中通过某种手段弄到级附魔的过程,被基岩版玩家们亲切地称为『32k』。 其实,如果使用一些作弊软件的话,可以更快速的弄到级的附魔,而且这种方法适用于网易租贷服。只不过......风险......会很大。 第一百零五章 属性修饰符 上-哪个mc玩家不想拥有一套神装呢? 在minecraft中,最厉害的神装是怎样的? 在了解这一章的内容之前,你估计认为minecraft最厉害的神装就是: →手拿下界合金剑(锋利、耐久、亡灵杀手、戒指杀手........lv.) →身裹残骸(保护、耐久.......lv.) →满满一潜影盒的附魔金苹果 这就是神装。 但这是最厉害的神装吗? 并不是,因为我们还可以堆料——使用mojang官方提供的minecraft内置属性修改器: attributemodifiers [mojang?]修改器 等等,什么是属性修改器? 『属性修改器』,确切的来说,是『属性修饰符』(attribute modifiers)。它是一种能够修饰属性的东西。 什么是属性? 属性(attributes)是minecraft中生物和玩家身上的增益\/减益特性系统。比如你的最大生命值、攻击速度、攻击距离等等,这些都是你的属性。 我们可以直接修改属性的基础值,也可以在属性上加上『属性修饰符』对属性的值进行一个修饰。比如,你可以为你的最大生命值加上一个修饰符,就可以将最大生命值提高到2048点。你也可以直接修改最大生命值的基础值,但这种直接修改和通过属性修饰符修改有很大不同,以后会讲到它们的差别。 那怎么添加属性修饰符呢? 有两种办法:1使用\/attribute指令2使用nbt 至于第一种办法我们以后再讲,这两章我们就来了解使用nbt该如何添加属性修饰符。更确切地说,我们接下来要研究的是:如何给物品添加上属性修饰符。 需要注意的是,物品没有属性,因此给物品添加上属性修饰符,本质上就是通过物品这个载体给拥有此物品的玩家\/生物添加上属性修饰符。 物品的属性修饰符存储于物品nbt的attributemodifiers标签下。attributemodifiers标签的数据类型是『复合标签列表』,其中的每一个『复合标签』都代表着一个『属性修饰符』: {attributemodifiers:[{属性修饰符},{属性修饰符}......]} 每个属性修饰符都具有如下标签: attributename(文本)——此属性修饰符要修饰的属性 name(文本)——此属性修饰符的名称 slot(文本)——此属性修饰符生效的栏位 operation(int整形)——修饰的运算模式 amount(double浮点数)——修饰数值 uuidmost(int整形)——这个修饰符的uuid的高位[je1.16删除] uuidleast(int整形)——这个修饰符的uuid的低位[je1.16删除] uuid(int整形数组)——这个属性的uuid[je1.16新增] 在具体使用属性修饰符之前,让我们先来了解下都有哪些属性: \\\\基础属性\\\\ generic.max_health——最大生命值[0.0~1024.0] generic.movement_speed*——移动速度[0.0~1024.0] \\\\攻击相关\\\\ generic.attack_damage——普通攻击伤害[0.0~2048.0] generic.attack_knockback——攻击击退力度[0.0~???] generic.attackreach?——玩家攻击距离[0.0~6.0] generic.attack_speed——玩家攻击的速度[0.0~1024.0] \\\\防御相关\\\\ generic.armor——盔甲防御点数[0.0~30.0] generic.armor_toughness——盔甲韧性[0.0~20.0] \\\\玩家的其他属性\\\\ generic.reachdistance?——玩家的触及半径,也就是你的手有多长[0.0~256.0] generic.luck——玩家幸运度[-1024.0~1024.0] \\\\更多属性\\\\ generic.follow_range——生物追踪距离[0.0~2048.0] generic.knockback_resistance——生物抗击退效果[0.0~1.0] generic.flying_speed*——鹦鹉的飞行速度[0.0~1024.0] horse.jump_strength*——马的弹跳力[0.0~1.0] zombie.spawn_reinforcements——僵尸攻击一次在周围生成另一个僵尸的可能性[0.0~1.0] 注:『*』代表此属性的度量标准不明,『?』代表此属性还未正式启用。 这些就是minecraft java截止1.19.1版本的所有属性。 让我们来试一试,创建一个能够修改最大生命值的属性修饰符: {attributemodifiers:[{attributename:“generic.maxhealth“}]} \\\\适用于java1.6.1~1.15.2\\\\ {attributemodifiers:[{attributename:''generic.max_health''}]} \\\\适用于java1.16及以上版本\\\\ 上面仅仅指定了该属性修饰符要修饰的属性,我们还需要给这个修饰符添加更多的信息才能使其生效。 首先,我们需要添加name标签,用于指定该修饰符的名称: {attributename:xxxx,name:“修饰生命值用“} 如你所见,name标签的值随便填,只要合规就可以。 其次,作为一个物品的属性修饰符,我们需要使用slot标签指定该修饰符要在物品放在哪个地方时才会生效。slot标签虽然说填的是栏位,但游戏只允许我们选择下面六个栏位: mainhand——拿在主手时才起作用 offhand——拿在副手时才起作用 feet——套在脚上才有用 legs——穿在腿上才有用 chest——当作胸甲穿才有用 head——顶在头上才有用 比如我们可以指定要把物品拿在副手时才起作用: {attributename:xxxx,name:xxxx,slot:“offhand“} 第三,作为一个修饰符,肯定要通过amount标签指定修饰的数值。amount标签的数据类型是double双精度浮点数,你在这把它当做普通的浮点数来看就行了。 我们可以指定修饰的数值为5: {......,amount:5.0} 但需要注意的是,这里的数值并不代表最终修饰成的属性值。最终的值除了看amount标签,还要看operation标签指定的是什么运算模式。 operation的作用是『用来指定修饰的计算模式』,也就是『这个修饰符要怎样修饰原来的属性』。它可以指定三个值,分别对应三种计算模式: 0——属性增量(也就是直接加上去) 1——倍率增量(并不是简单的乘上去) 2——最终倍乘(和倍率增量有点像) 我们先来看看『属性增量』计算模式,它是这样计算的: r=c+a c······属性基础值 a······amount标签值 r······结果 举个例子,假设有一个修饰符,它的数值为4.4,计算模式为『属性增量』,修饰的属性『玩家幸运值』基础值为2.5,那么该属性经过修饰后的结果就是: 6.9=2.5+4.4 如果有两个修饰符都是修饰『玩家幸运值』的呢?而且它们俩都是『属性增量』,且数值分别为2.4和9.1。 结果就是: 14=2.5+2.4+9.1 『倍率增量』的计算模式有点复杂,它是这样计算的: r=c?x(1+a) c?······属性基础值经过『属性增量』计算后的值 a······amount标签值 r······结果 1······基础倍率 举个例子,假设也有一个修饰符,它的数值为4.4,修饰的属性『玩家幸运值』基础值为2.5。但它的计算模式是『倍率增量』,也就是说属性的值经过它修饰后会变成: 13.5=2.5x(1+4.4) 这种只有一个修饰符的情况很简单。但如果是这样的情况呢: →有四个修饰符,分别叫作a、b、c、d。这四个修饰符的大致snbt标签如下: {attributename:幸运值,name:''a'',amount:4.1,operation:0} {attributename:幸运值,name:''b'',amount:3.6,operation:0} {attributename:幸运值,name:''c'',amount:1.7,operation:1} {attributename:幸运值,name:''d'',amount:2.5,operation:1} 属性『幸运值』的基础值为3.5。请问,该属性经过修饰后的值为多少? 答案是: 58.24=11.2x(1+1.7+2.5)=(3.5+4.1+3.6)x(1+1.7+2.5) 为什么是这样呢? 首先,游戏会进行『属性增量』计算,也就是: 11.2=3.5+4.1+3.6 然后,游戏会拿『属性增量』计算的结果再次经过『倍率增量』计算: 58.24=11.2x(1+1.7+2.5) 就得到了58.24这个值。 『最终倍乘』会在下一章讲到。在此之前,让我们看看最后的uuidmost和uuidleast标签。这两个标签该填什么? 看到uuid这四个字母时你估计已经知道这就是属性的id。 所以随便写,保证只要是数字就可以了。比如: {uuidmost:1,uuidleast:22} 至于1.16及之后的uuid标签,也一样,只不过从两个整数变成了四个整数: {uuid:[i;1,1,1,1]} 我们会在第一百一十章具体了解到uuid的相关内容。 最后,让我们把上面的东西结合起来,就可以得到: \/give @s diamond 1 0 {attributemodifiers:[{attributename:“generic.maxhealth“,name:“修饰生命值用“,slot:“offhand“,amount:5.0,operation:0,uuidmost:1,uuidleast:22}]} \\\\适用于java1.6.1~1.12.2\\\\ \/give @s diamond{attributemodifiers:[{attributename:“generic.maxhealth“,name:“修饰生命值用“,slot:“offhand“,amount:5.0,operation:0,uuidmost:1,uuidleast:22}]} \\\\适用于java1.13~1.15.2\\\\ \/give @s diamond{attributemodifiers:[{attributename:''generic.max_health'',name:''修饰生命值用'',slot:''offhand'',amount:5.0,operation:0,uuid:[i;1,1,1,1]}]} \\\\适用于java1.16及以上版本\\\\ 一个『在副手时』能够『+5 最大生命值』的钻石! 本章到此为止。 ——附录:属性的历史 java 1.6.1——加入了属性 1.7.2——属性现在可通过snbt用于指令中 1.9——加入了攻击速度属性、盔甲属性、盔甲韧性属性和幸运值属性。 1.14——加入了击退距离属性。 1.16——更改了大部分属性的id,加入了\/attribute指令。 bat test[即将到来]——正式加入攻击距离属性 携带版\/基岩版 0.12.1——加入了属性 ...... ...... ...... ...... 太棒了!一个特别棒的苹果: \/give @p apple{enchantments:[{lvl:255,id:“sharpness“}],attributemodifiers:[{operation:0,amount:2048,uuid:[i;1,1,1,1],attributename:“generic.attack_damage“,name:“a“,slot:“mainhand“},{operation:0,amount:1024,uuid:[i;1,1,1,2],attributename:“generic.attack_speed“,name:“b“,slot:“mainhand“},{operation:0,amount:1024,uuid:[i;1,1,1,3],attributename:“generic.max_health“,name:“c“,slot:“mainhand“},{operation:0,amount:30,uuid:[i;1,1,1,4],attributename:“generic.armor“,name:“d“,slot:“mainhand“},{operation:0,amount:20,uuid:[i;1,1,1,5],attributename:“generic.armor_toughness“,name:“e“,slot:“mainhand“},{operation:0,amount:1024,uuid:[i;1,1,1,6],attributename:“generic.luck“,name:“f“,slot:“mainhand“}],disy:{name:''“苹果手机“'',lore:[''“乔布斯开发的可以吃的苹果手机!“'']}} (乔布斯表示很淦) 第一百零六章 属性修饰符 下-最终倍乘和\/attribute指令 在上一章,我们了解了operation的『属性增量』和『倍率增量』计算模式,还有一个『最终倍乘』。那什么是最终倍乘呢? 『最终倍乘』是这样计算的: r=c?x(1+a?)x(1+a?)x......x(1+a?) c?=c?x(1+a?+a?+.....+a?) c?=c+m?+m?+.....+m? r······最终结果 a??...?······计算模式为『最终倍乘』的修饰符的amount值 a??...?······计算模式为『倍率增量』的修饰符的amount值 m??...?······计算模式为『属性增量』的修饰符的amount值 c?······『倍率增量』计算结果 c?······『属性增量』计算结果 举个例子,假设现在有这些修饰符: {attributename:''generic.max_health'',amount:5.0,operation:0} {attributename:''generic.max_health'',amount:3.0,operation:0} {attributename:''generic.max_health'',amount:2.0,operation:1} {attributename:''generic.max_health'',amount:1.5,operation:1} {attributename:''generic.max_health'',amount:1.1,operation:2} {attributename:''generic.max_health'',amount:0.1,operation:2} 当这些修饰符在一个玩家身上全部生效,且该名玩家的最大生命值仅仅受这些修饰符影响时,这名玩家的生命值上限将会从20.0点变成291.06点。这个『291.06』是这样得出来的: [(20+5+3)x(1+2+1.5)]x(1+1.1)x(1+0.1) ↓先计算『属性增量』↓ [28x(1+2+1.5)]x(1+1.1)x(1+0.1) ↓再计算『倍率增量』↓ 126x(1+1.1)x(1+0.1) ↓最后计算『最终倍乘』↓ 291.06 这就是『最终倍乘』,到这operation的全部内容也就讲完了。 但这不代表本章到此结束。还记得上一章提到的\/attribute指令吗?让我们来了解下这指令如何使用: \/attribute 作用:可以更改和读取属性 存在版本:java1.16-今 需要权限等级:java-2 需要作弊:是 格式: \/attribute <目标玩家\/生物><属性>[base] get [乘数] \\\\返回指定属性的『总值』。如果指定了base,则返回『基值』\\\\ \/attribute <目标玩家\/生物><属性> base set <值> \\\\将指定属性的『基值』设定为指定的值\\\\ \/attribute <目标玩家\/生物><属性> modifier add <名字><值>(add|multiply|multiply_base) \\\\如果没有uuid相同的属性修饰符,就给指定属性添加上属性修饰符\\\\ \/attribute <目标玩家\/生物><属性> modifier remove \\\\移除指定属性的具有指定uuid的修饰符\\\\ \/attribute <目标玩家\/生物><属性> modifier value get [乘数] \\\\返回具有指定uuid的属性修饰符的值\\\\ 使用这条指令可以很方便地修改实体的属性,以及为实体添加上属性修饰符。只不过由于\/attribute指令是直接给实体添加上修饰符,没有物品作为载体,所以在这边添加的修饰符无需指定『栏位』参数。 让我们来试一试,直接修改属性的值。比如,把我们的生命值上限改成40点: \/attribute @s generic.max_health base set 40.0 →实体xxx的属性最大生命值的基值已设置为40.0 很好,这下子我们就有40点生命值了。只不过要注意,玩家的属性会在死亡后重置,也就是说如果你死一次,最大生命值就会变回20点。 get子命令可以获得我们属性的总值或基值。总值也就是经过修饰符修饰后最终的值,基值也就是没有修饰过的初始值。比如: \/attribute @s generic.max_health base get 由于上面我们已经把基值改成了40.0,因此这将会返回: →实体xxx的属性最大生命值的基值为40.0 等等,这个『乘数』参数有什么用?让我们试一试: \/attribute @s generic.max_health base get 2.0 →实体xxx的属性最大生命值的基值为40.0 不难发现,这个乘数参数没有任何的用处.......呃,其实有用的。 用在哪呢?execute的store子命令: 1\/execute store result score @s health_max run attribute @s generic.max_health base get 2\/execute store result score @s health_max run attribute @s generic.max_health base get 2.0 指令1的返回值为正常的40.0,也就是将我们自己在health_max计分项上的值改为40。指令2虽然给我们的消息是40.0,但实际返回的是80.0,计分项上的分数也会改为80。 所以,『乘数』参数并不是没有用,而是它的用处在于影响指令的返回值。 修改属性还是很简单的。那使用\/attribute给实体添加修饰符呢?让我们再试一试: \/attribute @s generic.max_health modifier add 1-1-1-1-1 a 1.0 add →为实体xxx的属性最大生命值添加了修饰符00000001-0001-0001-0001-000000000001 在上面的指令中,使用了『modifier』子命令的『add』子命令来添加一个修饰符,参数『1-1-1-1-1』指定了该修饰符的uuid,『a』指定了该修饰符的名称,『1.0』指定了该修饰符的值,『add』指定了该修饰符的计算模式是『属性增量』。其中得讲一下的就是这个uuid参数。 在这边的uuid参数,填写的是『带连字符的十六进制uuid』。这种形式的uuid很常见,它长下面这样: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx 详细内容会在第一百一十章讲到,在这边你只需要把这东西当做填写五个用连字符『-』连在一起的整数即可: 1-1-1-1-1 上面的『add』参数所在的位置,也可以填写multiply_base(倍率增量)和multiply(最终倍乘),来改变运算模式。 现在,让我们看看的生命值上限是不是高达41.0: \/attribute @s generic.max_health base get →实体xxx的属性最大生命值的基值为40.0 ?怎么还是40.0?啊,是用错了,这获取到的是基值,应该把『base』参数去掉: \/attribute @s generic.max_health get →实体xxx的属性最大生命值的值为41.0 很好,所以你现在会用\/attribute给实体添加属性修饰符了吗? remove和value get两个子命令的使用很简单,让我们试一试: \/attribute @s minecraft:generic.max_health modifier value get 1-1-1-1-1 2.0 →实体xxx的属性最大生命值中修饰符00000001-0001-0001-0001-000000000001值为1.0 上面这条指令会返回这个修饰符的值。并且由于指定了乘数为『2.0』,这条指令的返回值还会是『2.0』(1.0x2.0)。 \/attribute @s minecraft:generic.max_health modifier remove 1-1-1-1-1 →为实体xxx的属性最大生命值移除了修饰符00000001-0001-0001-0001-000000000001 这样子我们就删掉了刚刚给我们自己添加的属性修饰符,生命值上限回到了40.0。 本章到此为止。 附录:\/attribute历史 java 1.16——加入了\/attribute 第一百零七章 如何获取你在minecraft中的头 这章我们来讨论些可怕的东西。 你是否想过一个问题:如何在minecraft中获取你的头? 答案是肯定的,你甚至可以把它拿在手上,然后....... 挂在墙上(好滑稽啊啊啊啊啊!) (事实上真的有个java服务器这么做了) 问题来了,怎么获取你的头呢? 这个时候就要用到头颅这个物品。 你应该知道,正常头颅的皮肤是steve(史蒂夫)的头,也有骷髅、僵尸等怪物的头。 但你知道吗?你可以改变头颅的皮肤——变成其他玩家的。 头颅具有一个数据类型为文本的skullowner标签,你可以在这个标签内写上一个玩家的名字,然后就可以获取到这名玩家的头。比如我们籽岷大大的minecraft正版用户名是zi_min,你就可以: \/give @s minecraft:skull 1 3 {skullowner:“zi_min“} \\\\java1.13以下版本\\\\ \/give @s minecraft:yer_head{skullowner:“zi_min“} \\\\java1.13及以上版本\\\\ (近日一外国小哥在minecraft获得了籽岷的头,那么它是怎么.......) 需要注意的是,上述方法仅仅适用于下面两种情况: 1你是通过离线账户来游玩minecraft的 2你是通过正版账户来游玩minecraft的 为什么呢?因为游戏之所以能够获取到对应玩家的头颅,是因为游戏向mojang官方服务器发送了请求,然后官方服务器再把这个皮肤数据传送回来,其过程有些类似于玩家登录服务器游玩。因此,当你在某离线或正版java服务器中运行上述指令,腐竹就有可能在某一天无聊翻看服务器根目录的usercache.json文件时惊喜的发现: {“name“:“zi_min“,“uuid“:“1aa95b71-48fc-4636-962b-e95de5071da6“,“expireson“:“202x-xx-xx xx:xx:xx +0800“} (???籽岷来玩我服务器了?) ....... 等等,你在运行上述指令后,只是获取到普通的玩家头颅,或者说获取到了看起来不是籽岷皮肤的头颅? 如果你仅仅是获取到普通的玩家头颅,那大概率是你的问题: 1你写错了 2你网断了 3你用的基岩版 4你在单人游戏中尝试,且没有打开『对局域网开放』 5你的电脑或服务器无法连接到官方服务器 6你电脑的防火墙阻止了你的minecraft访问官方服务器 但如果你获取到了看起来不是籽岷皮肤的头颅,那就肯定是这个问题: 您正在使用外置登录游玩minecraft 什么是『外置登录』? 我们知道,minecraft的正版玩家能够登录并显示皮肤,是因为minecraft游戏本体向官方服务器发送了玩家的登录信息,服务器经过验证无误后再返回皮肤等信息,最终你在游戏中的角色就有了皮肤。但对于一个没有正版账号的minecraft玩家来说,发送一个虚假的登录信息给官方服务器肯定是不行的。那该如何让盗版玩家也能够享受上皮肤的好处呢? 要解决这个问题很简单。盗版玩家之所以无法显示皮肤,是因为将『虚假的登录信息』发送给了『正版服务器』。如果我们自己搭建一个盗版服务器,然后再让minecraft将这个『对于盗版服务器来说是正确的但对正版服务器来说是虚假的登录信息』发送给『我们自己的盗版服务器』,这样子负负得正,我们发送的信息也就成为了『正确的登录信息』,minecraft也就可以获取到『盗版服务器』传来的皮肤,最终在游戏内显示出来。 这就是『外置登录』的原理。在真正的『外置登录』中,各大皮肤站就是『盗版服务器』,我们在各大皮肤站注册的账号就是『对于盗版服务器来说是正确的登录信息』。当我们在诸如hmcl、pcl2之类的minecraft java第三方启动器中输入『对于盗版服务器来说是正确的登录信息』和该信息对应的『盗版服务器』,再让启动器以『外置登录』的方式启动时,minecraft就会尝试发送『对于盗版服务器来说是正确的登录信息』给『正版服务器』。 (等等,这样子的话哪里会验证成功啊?) 别急,好戏还在后头。 当启动器检测到minecraft正将『对于盗版服务器来说是正确的登录信息』发送给『正版服务器』时,启动器会以迅雷不及掩耳之势,在消息还未发送到正版服务器时,就一把夺过minecraft与『正版服务器』的通信,把这个通信从『正版服务器』上拔下来,插到指定的『盗版服务器』上面去。此时『对于盗版服务器来说是正确的登录信息』就不会发送给『正版服务器』,而是发送到对应的『盗版服务器』。『盗版服务器』在收到登录信息后,验证通过,发送皮肤等信息给minecraft,minecraft此时就会认为该登录信息正确,允许玩家登录游戏并显示皮肤。 上述过程十分完美,但由此会产生出一个问题: 当我们通过指令获取指定玩家的头颅时,游戏本应该会发送请求给『正版服务器』,但启动器这么一操作就使得信息往『盗版服务器』那边发,最终导致我们获取到『盗版服务器』上对应玩家的头颅,而不是我们想要的正版玩家头颅。 举个例子。假设你想要获取到籽岷的头颅,这时候你就会尝试通过上述指令获取。如果你用的是离线或正版登录,那没什么,游戏可以正常从官方服务器那边拿到正确的头颅。但如果你是在littleskin(一个皮肤站)上注册了一个账号,然后通过外置登录游玩minecraft,此时你再尝试获取籽岷的头颅,就不会获取到正版玩家『zi_min』也就是籽岷的头颅,而是littleskin这个皮肤站上『zi_min』这个玩家的头颅。如果这名玩家也用的是籽岷皮肤那也没什么,但如果ta用的是其他的皮肤,你就可能会疑惑『籽岷怎么改皮肤了?』。 这就是为什么用外置登录会获取到错误头颅的根本原因。 另外,网易我的世界虽然不是外置登录,但也和外置登录很类似——网易修改了minecraft java的源代码,使得皮肤请求会往网易服务器那边发。因此如果你在网易我的世界中尝试获取籽岷的头,实际上也无法获取到正确的头,仅仅只能得到网易服务器上『zi_min』玩家的头颅。 上面这些便是获取到指定玩家头颅的办法。但本章还未结束,因为在这,mojang埋了一个大大的彩蛋: mojang是个好心人,他给了我们一些特殊的头颅。 这些头颅大多数是动物的,但其中不乏一些特别神奇的头颅。 没错,就是那个被玩梗玩到飞起的herobrine! (只不过这herobrine的胡子好像被剃须刀刮掉了) 下面是名单: mhf_alex——alex的头 mhf_ze——烈焰人的头 mhf_cavespider——毒蜘蛛的头 mhf_chicken——鸡的头 mhf_cow——牛的头 mhf_creeper——苦力怕的头(creeper?) mhf_enderman——小黑的头 mhf_ghast——恶魂的头 mhf_golem——铁傀儡的头 mhf_herobrine——吾王herobrine的头 mhfvaslime——地狱史莱姆的头(我忘记这怪物叫啥了) mhf_mushroomcow——蘑菇牛的头 mhf_ocelot——豹猫的头 mhf_pig——猪的头 mhf_pigzombie——猪人的头 mhf_sheep——羊的头 mhf_skeleton——小白的头 mhf_slime——史莱姆的头 mhf_spider-蜘蛛的头 mhf_squid——鱿鱼的头 mhf_steve——steve的头 mhf_viger——被砍了鼻子的村民的头(村————民————) mhf_wskeleton——凋零骷髅的头 mhf_zombie——僵尸的头 (奇怪了?herobrine的好兄弟notch的头去哪了?) (其实获取notch的头并不需要在前面添加上mhf,因为notch本身就有mc帐户) 但mojang不止砍了动物以及玩家的头,还饶有兴趣地把目光放在了部分方块上。 于是名单上又多了: mhf_cactus——缩水的仙人掌 mhf_cake——小蛋糕 mhf_chest——小箱子(并不能放东西) mhf_coconutb——棕色的椰子 mhf_coconutg——绿色的椰子 mhf_melon——在贫瘠土地上生长的西瓜 mhf_oaklog——在贫瘠土地上生长的木头 mhf_present1——绿色的.......礼包? mhf_present2——红色的........礼包? mhf_pumpkin——在贫瘠土地上生长的南瓜 mhf_tnt——被做成标本的tnt mhf_tnt2——被做成标本的tnt(另一个材质) mojang不止把心思放在了动物和方块上(还有一些彩蛋),还把目光投向了地图制作者。 于是他们给地图制作者添加了以下几个比较有用的头颅: mhf_arrowup——朝上的箭头 mhf_arrowdown——朝下的箭头 mhf_arrowleft——朝左的箭头 mhf_arrowright——朝右的箭头 mhf_exmation——一个感叹号 mhf_question——一个问号 这一章到此为.......奇怪了这存档里所有树的树叶都被偷了? 这到广 ...... ...... ...... ...... 附录:头颅历史 java 1.4.2——加入了头颅。此时虽然可以获取自定义头颅,但只能通过修改游戏的nbt文件才能实现。 1.7.2——现在可通过指令获取到自定义头颅。 1.8——骷髅、僵尸、苦力怕和凋灵骷髅的头颅可通过相应生物被闪电苦力怕炸死来获得。 1.8.4——自定义玩家头颅的来源现在只能是官方服务器。 1.9——加入了龙首。 1.13——头颅的命名空间id被改变。 携带版\/基岩版 0.12.1——加入了头颅 1.0.0——加入了龙首 祝贺minecraft11周年生日快乐! 今天,5月13日,是minecraft的第11周年。 从2009年5月13日minecraft正式发行,到2020年5月13日,已经过去了11个年头,也陪伴了我们11年。 11年,相当于一个人从出生到上小学五年级,占了人类(平均)寿命超过1\/7! 在此,我们祝贺minecraft,11周年生日快乐! (为什么感觉好像是升国旗似的) minecraft 2009-2020大事记 →2009年 5月13日——minecraft发行第一个版本:ssic 0.0.9a 8月4日——首次出现生存元素 12月23日——minecraft进入indev开发阶段,发布indev 0.31 →2010年 1月13日——minecraft注册用户突破名。 1月29日——加入了合成系统 2月27日——加入无限地图 7月3日——加入红石 9月18日——加入潜行 10月16日——mojang ab创立 10月30日——加入下界 12月20日——minecraft进入beta开发阶段,发布beta 1.0 →2011年 1月12日——minecraft销量超过100万 6月30日——加入活塞 7月1日——minecraft注册用户超过1000万 8月16日——mojang发布携带版alpha 0.1.0 11月17日——第一款ios携带版发布:携带版alpha 0.1.2 11月18日——minecon 2011 在内华达州拉斯维加斯市的曼德勒海湾举行。同一天,官方发布minecraft java 1.0版本。 →2012年 2月11日——携带版alpha 0.2.0在android发布 3月1日——java 1.2.1 发布 8月1日——java 1.3.1发布 10月25日——java 1.4.2骇人更新发布 11月24日——minecon 2012在法国巴黎的迪士尼举行 11月25日——minecraft java1.5红石更新公布 →2013年 3月13日——java 1.5红石更新发布 4月1日——愚人节更新 7月1日——java 1.6.1马匹更新发布 10月25日——java 1.7.2改变世界的更新发布 11月2日-3日——minecon 2013在佛罗里达州奥兰多市的橘郡会议中心举行 →2014年 2月26日——minecraft java 1.7.5发布 4月9日——minecraft java 1.7.8发布 4月14日——minecraft java 1.7.9发布 6月26日——minecraft java 1.7.10发布 9月2日——minecraft java 1.8缤纷更新发布 9月15日——mojang及其作品minecraft被microsoft以25亿美元(约合人民币153.26亿元)收购。 11月8日——notch正式宣布离开mojang ab 11月24日——minecraft获得英国电影和电视艺术学院奖的儿童表决奖 11月25日——minecraft java 1.8.1发布 →2015年 2月16日——超过5000个学校使用minecraft概念课堂 3月27日——minecraft java版和mac版销售量达到份 4月1日——minecraft 1.10快照15w14a愚人节更新发布 6月30日——minecraft java版销售量突破2000万 7月4-5日——minecon2015在伦敦举办 7月29日——minecraft 1.9 的第一个快照(15w31a)发布 12月9日——minecraft java版1.8.9发布 12月26日——《迷你世界》正式发行(说实话这个必须提) →2016年 1月19日——minecraft教育版发布 2月29日——minecraftjava版1.9“战斗更新”发布 5月20日——mojang与网易发布新闻稿宣布在中国发行携带版以及java版 6月2日——minecraft在各平台上共销售1亿份,并且成为有史以来第二畅销的电子游戏 6月8日——minecraftjava版1.10霜炙更新发布 6月13日——携带版alpha 0.15.0“友好更新“发布。 9月24-25日——minecon 2016在美国加利福尼亚州的安纳海姆举办 11月1日——minecraft:教育版正式发布 11月14日——minecraftjava版1.11探险更新发布 →2017年 4月7日——我的世界中国版封闭测试在bj被宣布;我的世界中国版发布会在bj水立方举行 6月1日——基岩版1.1.0发布 6月7日——minecraftjava版1.12(即多彩世界更新)发布 7月14日——我的世界中国版开启不删档测试 8月8日——minecraft中国版开始进行公开测试 9月15日——minecraft中国版的ios版公测 9月20日——基岩版1.2.0独乐不如众乐更新发布;我的世界中国版的android版开始限号不删档测试 11月18日——minecon earth;minecraft1.13水域更新宣布 →2018年 1月19日——minecraft达到7400万活跃用户与1.44亿总销量 7月18日——minecraftjava版1.13“水域更新”发布 8月28日——基岩版1.6.0发布 10月15-16日——基岩版1.7.0发布 12月11日——基岩版:1.8.0发布 →2019年 1月11日——彼得·苏列特被确认成为《minecraft: the movie》的导演,同时该电影部分剧情的大纲被公布 2月5日——基岩版1.9.0发布 3月19日——基岩版:1.10.0发布 4月3日——《minecraft:java版》的销量超过3千万 4月23日——村庄和掠夺”作为java版1.14和基岩版1.11.0发布 5月7日——ssic 0.0.23a_01的重制版被上传至ssic.minecraft来庆祝minecraft十周年 5月17日——minecraft销量超过俄罗斯方块,成为史上销售最多的视频游戏;mojang ab宣布了minecraft earth;minecraft自第一个公开版本java版ssic 0.0.11a发布起正式十周年 7月7日——minecraft earth被宣布将在7月晚些时候在选定的城市进行封闭测试 7月9-10日——基岩版:1.12.0发布 8月14日——教育版1.12发布 9月28日——minecon live 2019举行,宣布了下界更新和minecraft earth的发布日期,以及minecraft festival的举办日期 10月29日——基岩版1.13.0发布 11月9日——我的世界中国版2019年开发者大会举行;我的世界中国版全平台用户将近3亿 11月20日——基岩版1.13.3 发布 12月10日——java版1.15发布,基岩版1.14.0发布 →2020年 2月5日——java版1.16的首个快照(20w06a)发布 3月——新型冠状病毒(2019-ncov)疫情全球爆发 3月31日——mojang确认minecraft dungeons在中国大陆将继续由网易代理 4月28日——迷你世界因涉黄全平台关闭下载渠道,但并没有关闭服务器,玩家仍能照常游玩 5月13日(今天)——minecraft自发行以来的第11年 mc不倒,陪你到老,mc要倒,我们扶好! 此生无悔入mc,来世还做方块人! 第一百零八章 掉落物的nbt 上 -物品通用标签 物品的nbt就先讲到这,如果你还想了解更多,可以前往minecraft wiki搜索词条『yer.dat格式』,里面写了很多常用的物品标签。从这一章开始,我们就要开始学习实体的nbt。 ....... 如果你看过『作品相关』的: 『如何制作一个起床战争资源点』 (现在不推荐你看这一章) 那你应该知道,在java版,除了那一章讲的方法以外,还可以使用\/summon指令来快捷生成掉落物。而这种方法的核心,就是:掉落物(minecraft:item)的nbt。 (什么?mojang改名了?logo也改了?微软为了庆祝minecraft11周年改的?) ————一个并不怎么华丽的分割线———— 钻石<——看!你掉了一颗钻石在这! 你知道,如果你不在五分钟内捡起它的话,那么你幸幸苦苦挖到的钻石就会凭空消失。 你也知道,如果这颗钻石掉进岩浆,或碰到仙人掌和火焰,那么这颗钻石也会消失。 但你可能不知道,上面这些,都是写在掉落物的nbt里的。 接下来,让我们进入钻石(掉落物)的nbt里,来研究研究: {age:0s,health:5s,pickupdy:0s,item:{count:1b,id:“minecraft:diamond“} ↑↑↑这是你掉的钻石的nbt,需要注意这只不过是一个简化版↑↑↑ 其中,age标签的数据类型为short短整型,它唯一的作用是记录『这个物品已经掉落多长时间,以方便游戏清除掉落时间过长的物品』,它的单位为『游戏刻』。此时age标签的值为0,说明这个钻石刚刚才掉落。该标签实际可发挥作用的值范围为『-~6000』,如果设置为『-』,那么这个物品将会一直存在于这里(没错,你就不用担心死了之后跑回来在要捡起物品时物品突然消失所导致的德国boy行为了)。 那如果到了6000呢?恭喜,你的物品违反了能量守恒定律凭空消失了。 然后是health,你肯定会很惊讶为什么掉落物也有生命值呢?实际上小编也—— 实际上我不惊讶,因为我早就知道了 health标签的数据类型也是short短整型,它的值决定了你的物品的抗火焰、岩浆以及仙人掌的能力(想攻击一个掉落物?做梦!),游戏默认值为5,当为0时就会被销毁。 如果你不想让你的钻石被熔岩焚毁,就可以尝试修改修改这个health标签的值。 于是——震惊mc科学界的发现!碳元素组成的钻石竟然在超高温下仍然健在! (这样子就可以解释为什么那些坑新手的mc教程里,钻石扔进熔岩并没有被销毁了。) →记住:永远不要和mc讲科学 pickupdy这个标签有点有趣。在介绍这个nbt标签之前,先让你了解了解一个掉落物的细节: 假设现在将钻石扔到你的脚下,你会发现:钻石在落地后并没有马上被你捡起,而是过了一两秒之后,才被你捡起来。 (如果在很土豆的服务器,这个时间会更长) 为什么会这样呢? 就是因为pickupdy标签。 pickupdy标签的数据类型也是short短整型,它的值代表着掉落物剩下不能被捡起的时长,每游戏刻它的值都会减少1,当它的值减到0时就代表掉落物可以被玩家捡起。 就因为这个标签,导致你扔出去东西后不会立马回到你的身上,而是要等一会儿。 如果你将这个值设定为,那恭喜你——你永远也捡不起这个钻石了,因为设定为后,这个值将不再会减少。 item标签的数据类型是复合标签,它存储着该掉落物的核心——物品的信息。那这物品的信息到底是通过哪些标签储存的呢? 接下来,容许我隆重介绍minecraft中三大通用标签之一的: 物品通用标签 『物品通用标签』具有下面几个标签: count(byte字节型)——物品堆叠的数量。 slot(byte字节型)——物品所在的栏位(很多情况下不会有这个标签)。 id(string文本|je1.8前只支持数值)——物品命名空间id。神奇的是如果你不填,那么游戏会把物品认成石头。 damage(扁平化中被换职|short短整型)——物品数据值 tag(复合标签)——关于当前物品的额外信息,我们前几章了解的各种物品标签其实都存储在这个复合标签里面。 举个例子,假设你的副手拿着三颗附魔了锋利i的钻石,那么这三颗钻石的物品nbt标签就是: {count:3b,slot:-106b,id:“minecraft:diamond“,tag:{enchantments:[{id:“minecraft:sharpness“,lvl:1}]}} \\\\适用于java1.13及以上版本\\\\ {count:3b,slot:-106b,id:“minecraft:diamond“,damage:0s,tag:{ench:[{id:16,lvl:1}]}} \\\\适用于java1.8~1.12.2版本\\\\ 其中,『count:3b』代表有3个物品,『slot:-106b』代表该物品在副手栏位(副手栏位的号码为-106,注意这里的栏位号码不等同于栏位id),『id:“minecraft:diamond“』代表该物品是钻石,『tag』下的『enchantments或ench』规定了该物品的附魔情况。对于扁平化前的版本来说,『damage:0s』还代表着该钻石的数据值为0。 『物品通用标签』中唯一需要注意的是id标签,id标签在mc历史上有很多改变。在java1.8以前,它的数据类型为short短整型,存储的是物品的数字id。而1.8之后,mojang渐渐抛弃了数字id,id标签的数据类型也就变成了string文本(字符串)类型,用来存储物品的命名空间id。 现在,让我们尝试生成一个钻石。等等,这个damage标签,不是已经在第一百零三章就出现了吗,为什么这里又出现了呢? 因为这个damage标签在扁平化之前,也是物品通用标签的一份子,用来储存这个物品的数据值。1.13扁平化之后,数据值没了,这个damage标签就被mojang调到tag下面成为物品的『损坏值』。 所以存在于物品tag标签下的damage标签,是je1.13更新中才出现的。je1.13以前的损害值,就直接和物品数据值结合在一起(就像现在的基岩版一样)。 现在,让我们正式生成一个钻石: \/summon item ~~-2 ~{age:0s,item:{count:1b,id:“minecraft:diamond“}} \\\\适用于java1.11及以上版本\\\\ \/summon item ~~-2 ~{age:0s,item:{count:1b,id:“minecraft:diamond“}} \\\\适用于java1.8~1.10.2\\\\ \/summon item ~~-2 ~{age:0s,item:{count:1b,id:264s}} \\\\适用于java1.7.2~1.7.10\\\\ 你可能注意到了,这条指令的生成位置是在脚底下两格处。为什么要这样做? 答案你应该知道:因为我们没有指定pickupdy标签,游戏在生成时就会默认它为0,就容易导致钻石一生成还没落地就被我们吸走。 所以现在你知道该如何制作一个高端大气上档次的起床战争资源点了吗?别忘记把age设成-了! 本章到此为止。 附录:掉落物和物品通用标签的历史 java 0.24——加入了掉落物 1.3.1——同一处的同一类型掉落物现在会自行堆叠 1.8——物品通用标签的id标签的数据类型从short短整型改为string字符串 1.11——实体id从item变为item 1.13——物品通用标签的damage标签被移到tag标签下,数据类型从short短整型改为int整型。 携带版\/基岩版 0.2.0——加入了掉落物 ?——物品通用标签的id标签被name标签替代 第一百零九章 掉落物的nbt 下 (此章节内容不怎么重要,可跳过此章节) 众所周知,使用\/give指令可以让你获得指定的物品。 比如指令『\/give @s mand_block』的作用就是让你获得一个命令方块。 但你知道你是怎么获得这个命令方块的吗? 在你运行该指令的那一刻,这条指令会被游戏进行处理,然后你就获得了这个命令方块。奇妙的是,在java版,你似乎并不是直接获得命令方块,而是捡起了一个命令方块掉落物。 如果那真的是一个掉落物的话,那么这个掉落物的属性是什么呢? pickupdy标签的值肯定为0,age标签很有可能是6000。 但此时又有一个新的问题出现了:如果是在服务器中,你站在茫茫人海,但这个掉落物仍然被你精准地捡起了,这是为什么呢?(说实话还没等你捡起你家宽带以及你的电脑就要主机火苗万丈高了) 因为掉落物的nbt还有一个可能不存在的标签:owner owner标签的数据类型是复合标签,在java1.16及以上版本是int整型数组。它的值本质上是一个玩家的uuid,用来决定这个掉落物可以被哪个玩家捡起。 举个栗子,假设有这么一个叫做『liu_huaqiang』的玩家,如果你要生成一个只能够被它捡起的掉落物,那owner标签就得这样子填: {owner:{uuidmost:l,uuidleast:-l}} \\\\java1.16版本以下\\\\ {owner:[i;,-,-,]} \\\\java1.16及以上版本\\\\ 其中,uuidmost和uuidleast这两个标签填的是这名玩家的uuid高位和uuid低位。我们会在下一章讲到uuid。 这就是owner标签的用法,只不过你现在其实并不需要急着去用,因为掉落物还可能会有一个标签。 假设你在矿洞挖矿,刚刚挖到8颗钻石,你很兴奋,然后听到后面有一个........ “嘶~~~” 你转头一看:“creeper?” “booooom!” 恭喜你,你的钻石成为了一个掉落物。 这颗钻石掉落物的nbt也值得研究。 它的nbt除了上一章所说的,还有一个你从未见过的nbt标签: thrower——这个物品本来是谁的 和owner一样,它的值也是一个玩家的uuid信息。当某名玩家把这个物品以某种形式丢掉了,这个物品的thrower标签就会存储该名玩家的uuid。 thrower的用法和上面的owner一模一样,这里就不细讲了。 这一章到此为止。 easecation真好玩——唉,好像作业还没做唉。 附录:历史 java 1.16——为适应新版本的uuid,owner和thrower标签的数据类型从复合标签改成int整型数组。 第一百一十章 uuid 在minecraft java 1.7.10版本更新中,mojang认为玩家可以更改用户名。但如果玩家可以更改用户名,那么一个用户名就不能完全代表一个玩家。解决这个问题的唯一办法,就是给玩家添加一个从按下注册那一键开始就不能改变的唯一识别码。 使用什么样的识别码呢?mojang直接就采用了不管是在minecraft中还是在网络上都十分常用的『universally unique identifier』来作为玩家的不可改变识别码,这就是作者在之前经常提到的uuid,它的中文名叫做『通用唯一识别码』。 一个uuid本质上是一个长达128位的随机生成的二进制数字,但我们不可能直接使用它的二进制形式,而是使用它的『十六进制』或『十进制』形式。 在十六进制中,最常见的形式就是: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx 这是uuid的『十六进制表示形式』。准确的来讲,是『有连字符的十六进制(hyphenated hexadecimal)』形式。这种形式的uuid本质上是将uuid转化到十六进制后,再用连字符『-』将其分割成8+4+4+4+12的5段。 当然,把连字符去掉就是纯洁的『十六进制形式(string without hyphens)』了: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 只不过去掉连字符的话,你有很大概率会抄错,所以还是建议在抄uuid之前给它加上个连字符。 什么?你不知道十六进制? 那你总知道十进制吧?在十进制中,数字是逢十进一。比如: 5+5=10 所以对于十六进制来讲,数字就是逢十六进一。比如: (5+5)+7=a+7=11 其中,字母『a』在十六进制中代表『十』这个数字。以此类推,b代表『十一』、c代表『十二』.......f代表『十五』。 这就是十六进制,你懂了吗? 回到正题。我们在第一百零六章时就已经遇到过『有连字符的十六进制』这种形式的uuid了。你还记得吗?让我们回忆一下: 『\/attribute @s minecraft:generic.max_health modifier value get 1-1-1-1-1 2.0』 其中,参数『1-1-1-1-1』就是一个『有连字符的十六进制』形式的uuid。等等,为什么这个uuid不是8+4+4+4+12的? 如果你有注意到游戏返回的消息,就会发现,这种uuid在游戏眼中会被视为: 『00000001-0001-0001-0001-000000000001』 也就是说,uuid中数字前面的0可以被省略。比如: 『00000101-0001-0003-0015-0000000』 上面这串uuid就可以省略成: 『101-1-3-15-』 这是一个非常人性化的设计,也非常符合数学。 需要注意,如果是『-1001-1001-1001-』这样的,可不要想着缩写成: 11-11-11-11-11 不然游戏会以为这个uuid是『00000011-0011-0011-0011-000000000011』的缩写。 这种缩写不仅仅在『有连字符的十六进制』形式中可用,在其他形式中照样可用。 现在你知道了十六进制形式的uuid。那之前的uuidmost(uuid高位)和uuidleast(uuid低位)到底是啥呢? 在解答之前,作者建议你先去找一个进制转换器,以方便现学现做。 以刚才的『00000001-0001-0001-0001-000000000001』举例,现在它是十六进制。 把前面三段(00000001-0001-0001)和后面两段(0001-000000000001)分开,并分别划成10进制,变成:和这两个数。 这两个数就是这个uuid的高位以及低位了。其实高位以及低位就是将十六进制的uuid切成两半然后划成10进制得出的数,说明白点,就是: xxxxxxxx-xxxx-xxxx 这一段转换成10进制就是uuid most xxxx-xxxxxxxxxxxx 这一段转换成10进制就是uuid least (在nbt中,这两个标签的数据类型都为long长整型) 但要注意,如果没有特别指明,你是不知道一个16进制的数字到底是正还是负。 原因的话,百度\/谷歌一下,你就知道(毕竟这是minecraft指令教学,不是计算机课)。 这种高位和低位的uuid形式,被称为『高低位(most\/least)』。这种形式在minecraft java1.16版本更新前几乎遍地都是,但在java1.16更新中却几乎绝迹了。 为何?因为在1.16版本更新后,nbt中大部分uuid再也不是『高低位』形式,而是使用了一个全新的表现方式:整型数组(int-array) 其样式我们在之前已经碰过好几次了。比如下面这一串: [i;-,,-,-] 好像这种形式的uuid和其他形式没有太大关系。 但其实这种uuid和其他形式的uuid也可以互相转换,不然正版玩家的uuid就得重新设置。 如果你不想了解的话,可以跳过这一段,去看看uuid到底该如何获取。 但如果你想了解的话,不妨也来看一看。 仔细观察这一串数组,你会发现这4串数字有正负号,并且没有出现字母,加上这是个『整型数组』。这些证据都证明,这四串数,是十进制。 既然是十进制,那就好办了。根据uuid most以及uuid least的经验,这四串数,极有可能是十六进制的uuid平均分成4段再分别划成十进制的数。 为了验证我们的猜想,先随机一个uuid: 十六进制——09fa22c0-807d-4a29-b0fa-a6513fab4822 数组形——[i;,-,-,] 将『09fa22c0-807d-4a29-b0fa-a6513fab4822』的连字符去掉,再平均分成4段,并取最前面的那一段,也就是: 09fa22c0 划成十进制就是:! 这种数组形式的uuid本质上就是将16进制形态的uuid平均分成四段再分别划成十进制最后组合成一个数组! 等等,遇到了一个小问题,这个负数问题,该怎么办? 百毒一下,你就知道。 说了这么多uuid,那么uuid该怎么获取? 如果你是一位java版的腐竹,开着一个服务器,那你就可以到服务器的根目录找到一个名叫usercache.json或usernamecache.json的文件,里面有全部服务器玩家的uuid。 对于java的正版玩家来说,有许多网站可以通过输入玩家的名字或uuid来查询一个正版玩家的皮肤、uuid等信息,甚至可以知道这个玩家去过哪些服务器,这些服务器现在有多少人在线,他的游戏时长是多少!虽然不知道这些数据是怎么获取的(极有可能是爬虫),但这也方便我们查询自己的uuid(以及别人的)。 比如最常见的mcuuid和namemc.。 但别忘了,实体也有uuid。那实体的uuid如何获取? 有很多种方法,你可以去网上搜。这里只讲一个最方便的: 在java1.13及以上版本中,使用聊天栏填写指令时,只要你的准心对着一个实体,在填写目标选择器类型的参数时你就可以通过tab键一键获取到这个实体的uuid(有连字符的十六进制形式)。 对了,正版玩家的uuid还可以通过mojang给出的api来获取,具体用法为: api.mojang.\/users\/profiles\/minecraft\/一个正版玩家的用户名 这里拿一个用户名叫做『minecraft』的正版玩家举例,输入api.mojang.\/users\/profiles\/minecraft\/minecraft,网页就会返回如下json: {“name“:“minecraft“,“id“:“bfae140c3b836a066c6debd8f“} 其中的id就是这名玩家的十六进制uuid。 附录:uuid历史 java 1.16——nbt中的uuid几乎都改成了整形数组的形式,抛弃了原有的高低位形式。 第一百一十一章 网易的特性:实体mod (该特性已被网易删除,因此此章节已作废,请跳过) 今天我们不聊nbt,我们来聊一聊网易的特性。 你应该知道如何去bugjump应聘: 面试员:当游戏遇到bug时,该怎么办? 你:那不是bug!那叫特性! 面试员(站起来和你握手):恭喜你,你被我们录取了。 (当然那是不可能的) 但作为国内的代理商——网易,其中国版也有特性吗? 答案是肯定的:有! 而且还是网易独占! 当你在网易使用\/summon时,你肯定没有去仔细研究里面的实体,除非你想在minecraft锻炼一下英文水平,在高考时取得更好的成绩,保送哈佛,然后........是不是扯得有些远了? 如果你把里面的实体仔仔细细研究一遍后,你就会发现里面有一个实体叫做:mod。 不要看着这个单词想太多啊,只是这个实体叫做mod,不是mod里叫做mod的实体。 当你召唤出来时,你就会发现这个mod实体只是一团圆形的影子(等等,mc里有圆?)。 真的只是一团影子吗?显然不是,不然为什么这个实体叫做mod,而不是shadow。 你肯定是创造模式,但当你想攻击这个影子时,你就会发现你根本就打不到任何东西!也就是无法使用道具销毁它!而且就连药水也奈何不了它。 但它就真的无敌吗?不是的,你可以通过岩浆、\/kill、火、虚空以及苦力怕的爆炸来摧毁。甚至可以通过活塞来移除。 当然,在移除之前,你得搞清楚这位mod在哪里,因为它是隐身的,没有ai,作者建议你使用\/particle+\/execute来添加个粒子效果,不然的话你连这位老兄在哪里都搞不清楚。 如果你开启了,那么你就会发现这个实体仍然在它出生的地方。没错,这个实体无法被外力推动,甚至可以违反牛顿的万有引力漂浮在空中! (听说牛顿的骨灰盒动了?) 什么,你想tp这位mod?来移动它?这确实是可行的办法,但如果你没有给这位实体上\/particle就tp,那么你就会发现这个实体的影子还在刚才的地方,没有tp。 这代表着什么呢?你肯定认为是无法通过tp来移动它的,但别忘了,刚才作者说的是:“这个实体的影子还在刚才的地方。”而不是:“这个实体还在刚才的地方。” 没错,tp这位神奇的实体,只会tp它,而不会tp它的影子,它的影子还在刚才的地方,非常的无奈。 所以这是否代表着我们可以通过mod实体来制作影子呢? (那么问题来了?怎么清除这个无奈的影子?用清除mod的方法就可以清除影子了。) 这是一个非常正确的想法,因为接下来,mojang可能会为这个特性实体震惊到眼珠子都掉在了地上,希望眼珠子没事(?我的手怎么打不开了?)。 用切割机打开手之后,你会发现这个mod实体它并没有碰撞箱,所以它只能通过指令来移动,并且玩家无法攻击到它。而这也方便了我们使用这个mod来制造一些更有趣的东西(比如说在minecraft玩minecraft?)。 为啥?因为这个实体没有碰撞箱,所以你可以正常的在它身上放置方块、破坏方块。特别是用于玩家特效的时候,一直tp到玩家身上,玩家仍然可以照常玩mc。 不得不说,这个实体是真的有用。 然而这还不是最厉害的。 还记得之前作者讲的ass(armor_stand_server:盔甲架服务器)服务器吗?虽然使用盔甲架是可以方便我们使用指令,但当很多个盔甲架服务器在常加载区块运行的时候,你的处理器就算是最高端的也已经有点喘不过气了。 为什么会这样?因为一个盔甲架,就算你不使用它运行指令,它仍然占用了相对于其他实体比较大的运算资源。 所以如果要使用多个服务器来运行指令,在国际版盔甲架是最好的选择,但在网易,你还有更好的选择: mod server(简称ms)服务器,不光名字缩减了,它的一单位占用的运算资源相对于盔甲架是少之又少。这里你可以做一个对比实验: 先召唤x个盔甲架(建议x至少大于50),体验一下卡顿的感觉。然后清除盔甲架,换成召唤x个mod,然后你就会发现卡顿的感觉大大减少(或者是几乎没有)。 也就是说,使用ms服务器可以大大减少卡顿,特别是在手机上,处理器没有电脑强,使用ms服务器来运算是比ass服务器会更加的棒。 缺点就在于你只能通过给ms添加tag或者是score来区分,无法通过命名牌来命名。 但最近网易砍掉了命名牌的功能,所以这时候选择ms比ass要更加的好。 综上所述,我们可以推断出这个mod实体到底是干什么用的。这个实体很有可能是帮助mod开发者开发mod的实体,所以才叫mod实体。这个实体就像是一个空白的纸张,等待着画师将它变成一篇旷世之作。所以我们也要担心网易什么时候会把ms服务器砍掉。 当然,那是以后的事情了(划掉这句话,已经被网易砍掉了)。 你以为这个mod实体就这些特性了吗?不止! 你应该知道实体有旋转角度这个概念,分为垂直旋转角度和水平旋转角度。 如果你给牛羊等动物进行旋转,只要指令一关闭,它们的头就会看向其他的地方。 而如果你给盔甲架旋转,水平旋转是没问题,但垂直旋转呢?一旦指令关闭,盔甲架的垂直角度就会被强制改为0度。 然而这种问题在mod实体上并没有出现,你可以使用它来进行正常的水平以及垂直旋转。能做到这种的实体除了mod,可能就只有玩家了(只不过非常耗费人力)。 所以,使用mod+\/execute+\/particle可以做出一个非常棒的粒子效果,适合在基岩版的服务器使用,当个装饰品。 (听说箭的朝向很奇特?) 但世界上没有东西是完美的,接下来的环节就是:mod的缺点。 在看了mod的这么多优点后,你是否想到可以给mod戴上一些东西来制造浮空的效果呢? 这是不可能的。 为什么这么说? 因为mod虽然是个实体,但它没有栏位,也就是无法使用\/receitem。 而且,刚才说过了,我们也不知道这个mod实体会在什么时候被砍掉。 好在,这个实体还在(划掉,已经不在了)。 mod实体的优点: 1.隐身,不易被熊孩子发现及破坏。 2.无碰撞箱,可以一直tp到玩家的身上且不会干扰玩家的正常操作。 3.占用的运算资源很少,可以方便作为指令服务器。 4.自身不会改变朝向 mod实体的缺点: 1.由于在国际版没有,这个实体就怕哪天被网易给移除了。 2.无法使用\/receitem指令 3.无法使用命令牌。 (等等,这个mod实体好像和弹射物实体极其相似?) (注:如果你是java版的,不必怀念mod实体。因为在java版,你有一个类似的选择:区域效果云[area effect cloud 简称aec]) 第一百一十二章 实体的通用标签 上 看,这是一头有胡子的粉红羊! (在哪?我怎么没看到?) 它作为一个实体,肯定也有自己的nbt标签。 在这些nbt标签中,有很大一部分是大部分实体通用的。 具体是哪些呢? 首先,和物品一样,游戏也会通过实体的nbt来识别该实体到底是什么实体,这就需要用到id这个标签。id标签的数据类型是文本(string字符串),它存储着这个实体的命名空间id。比如这只羊的id标签就是: {id:“minecraft:sheep“} 需要注意,id标签由于是用来判断实体类型的,十分重要,所以我们在游戏中无法通过指令来获取并修改它,也就是说你并不能把这只羊变成一只猪。另外,玩家虽然也是实体,但没有id标签。 id可以判断实体的类型,但如果游戏还想更精确地判断这个实体到底是哪个个体,就需要使用到uuid。实体的uuid数据也存储在自身的nbt中,也就是说我们可以通过nbt来获取到实体甚至玩家的uuid。 uuid的nbt存储方式在java1.16版本中迎来了巨大改变,这件事我们已经在第一百一十章了解过了。在java1.16之前,实体的uuid在nbt中是以『高低位』的方式存储,也就是像下面这样子: {uuidmost:l,uuidleast:-l} 其中,值后面的大写字符『l』代表这两个标签的数据类型都是long长整型。目前你只需要知道这种整型能够存储很大的数字即可。需要注意的是由于计分板数据类型是int整型,所以你并不能直接将实体的uuid高低位存进计分板中。 在java1.16更新后,实体的uuid改成了用int整形数组来存储: {uuid:[i;-,-,-,]} 由于改成了int整型数组的存储方式,所以在java1.16版本更新后,你就可以直接将实体的uuid存入计分板。 一个实体除了自身的类型和uuid,还有许许多多的数据。让我们仔细思考一下,可能还会有哪些数据。 一个实体肯定会有位置,所以nbt中自然也要存储实体的位置数据。pos标签就是干这个的。 pos的数据类型是『double双精度浮点数列表』,列表内的三个元素从左到右分别存储着该实体的x、y、z坐标数据。比如: {pos:[14.d,72.0d,133.d]} 这代表着该实体处于(14.,72,133.)这个位置。 和pos作用类似的标签还有rotation。rotation标签的数据类型是『float单精度浮点数列表』,列表内的两个元素分别记录着这个实体的水平旋转和垂直旋转角度。比如: {rotation:[322.f,0.0f]} 这代表着该实体正水平地朝向南偏东37.°的方向。等等!『322.』?! 还记得本书在第二十六章曾经写过这么几句话吗: 『等等,我们在讲tp时,不是说水平旋转角度是:「以实体为中心,以正南(z轴正方向)为0°,顺时针下来,实体朝向和正南方向的夹角(也或者说实体在真南方位角体系中朝向的角度),就是该实体的水平旋转角度。」 那这怎么跑出来负数了? 其实在minecraft中,水平旋转角度虽然可以像我们之前在第九章讲tp时那么用,但大多数时候,你都得这么用: 以正南(z轴正方向)为0°,顺时针旋转180°通过正西至正北,用正数,逆时针旋转180°通过正东至正北,用负数。比如-45°,就代表以正南为基准,逆时针旋转45°的方向;30°,就代表以正南为基准,顺时针旋转30°的方向。 也就是说,在minecraft中,水平旋转角度的正确范围是-180°~180°,而不是0°~360°。至于为什么我要在第九章那么讲,只是怕一下子就把负数搬出来会吓你们一跳。』 现在,我们要纠正这里的一个疏漏之处:在minecraft中,水平旋转角度其实有两套标准——一个就是我们在第九章讲到的『真南方位角』,也就是0°~360°这个标准;另外一个就是第二十六章讲到的-180~180°这套标准。 你可能已经有些晕了——两套标准,怎么判断什么时候要用什么标准? 其实很简单,我们只需要记住三个关键点就行: 1在目标选择器中,必须采用『-180~180°』这套标准。 2在指令中,除了目标选择器和nbt外,其他地方基本上两个标准都能用。 3在实体nbt中,玩家采用的是『-180~180°』这套标准,而非玩家实体采用的是类似『真南方位角』的0°~360°标准。 其中的第三点,这边得好好讲一下。回去看看上面那个rotation标签,你会发现那里采用的是『真南方位角』的标准,这说明了什么? 这说明,这个实体,不是一个玩家。 没错,上面那个rotation标签,是作者从java1.12.2版本中的一只猪上扒下来的。(不用担心,即使在目前最新的java1.19.1版本中,这个特性也没有被mojang改变) 那玩家的呢?让我们使用\/data指令获取一下: \/data get entity @s rotation \\\\适用于java1.13及以上版本\\\\ data指令本书还没讲到,如果你感兴趣的话可以去minecraft wiki上了解了解。在这边你只需要知道,上面那条指令可以获取到你自己(执行者)的rotation标签数据。 运行一下,游戏返回了以下数据: →xxxxxx拥有以下实体数据:[-71.f,29.f] 不难注意到,上面的数据中,水平旋转角度是『-71.f』,采用的是与非玩家实体不一样的标准。 so,你学会了吗?rotation标签就这样子,如果能的话你可以探究一下把实体的水平旋转角度设成负数会发生什么。接下来让我们继续了解更多的实体nbt标签。 实体肯定能够运动,因此必然具有速度属性。那游戏是怎样存储实体速度的呢? 我们在小学二年级就学过:一个物体的速度,可以被分解为该物体在x、y、z三个轴上的速度。minecraft中存储实体速度的方式就和这差不多。在实体nbt中,用来存储实体速度的标签是motion标签,它的数据类型是『double双精度浮点数列表』,列表内的三个元素从左到右分别是该实体在x、y、z三个轴上的速度向量,单位是『米\/秒』。举个简单的例子: {motion:[1.d,-0.75d,0.0d]} 这代表着该实体正朝着正东、水平向下约30°的方向以约1.5米每秒的速度前进。需要注意的是,motion的值并不会固定不变,而是会受到游戏模拟的阻力的影响。 (注:0.75倍根号3就约为1.,因此你可以把1.看作0.75√3) 由于本书并不是一个物理教材,所以关于motion我们就不继续深入,你大概知道是这么一回事就行。如果你没有看懂,可以去求助你的物理老师。 或者你可以去找一下那位屎尿屁专家?帮他完成屎尿屁大统一理论? 实体的nbt还有许多标签,好消息是这些标签相对上面的内容来说很简单。 air标签用于储存实体的『空气值』,它的数据类型为short短整型,允许的最高值为300,实体在水中每刻都会减去1,小于等于0时(对于大多数生物来说)会开始扣血。 falldistance标签很有趣。如果你玩过java版的老版本,那你可能知道在旧版本中,从高空落下而不被摔死的方法,除了落地水,还可以挑战手速按esc暂停游戏,然后再继续游戏。这个时候你的再掉下去就只会或几乎没有伤害。这个bug的核心就在于实体的falldistance标签。 falldistance标签的数据类型是单精度浮点型,它用来记录实体已经掉了多远的距离,然后在实体落地时计算会扣多少滴血。老版本暂停游戏的话,这个值就会清零,所以才会导致这个bug(于是mojang修复了)。 passengers标签是一个比较常用的标签,它的数据类型是『复合标签列表』,作用是记录骑着该实体的其他实体的nbt数据。没错,这东西可以用来套娃!ooc也就是用这个标签来制作的。 需要注意,在java1.9版本之前,实体并没有『passengers标签』,而是有『riding标签』。它的用法和新版本的『passengers标签』一模一样。 fire标签的数据类型是short短整型,它的作用是决定实体着火或不会着火的时长。如果它的值是正数,就是决定实体身上的火距离熄灭还有多少游戏刻,如果它的值是一个负数,则代表着该实体在接触到火后,不会着火的刻数。比如: {fire:-40s} 这代表着当该实体接触到火时,需要两秒才会燃起来。 portalcooldown标签的数据类型是int整型,作用是记录这个实体还有多长时间(单位为游戏刻)才可以再次穿越下界传送门。比如这只粉红羊刚刚穿过下界传送门,它就需要等至少300刻(15秒)才能再次传送,因为它的portalcooldow标签被设定为了300。 dimension标签的数据类型是int整型[java1.16以下]或文本(string字符串)[java1.16更新后],它的作用是记录该实体所处的维度。 举个例子: {dimension:“minecraft:overworld“} \\\\java1.16更新后\\\\ {dimension:0} \\\\java1.16更新前\\\\ 这代表着该实体所处的维度为『主世界』。对了,『下界』的维度数字id为-1,『末地』为1。 需要注意,似乎自从java1.16版本开始,dimension就不再是实体的通用标签之一,而是变成仅玩家拥有该标签。所以对于java1.16及以上版本的实体来说,并没有dimension这个标签。 这一章到此为止。 附录:实体通用标签的部分历史 java 1.9——riding标签改为passengers标签 1.16——dimension标签不再是实体通用标签,数据类型从int整型改为string字符串。 1.17——实体数据的储存位置被改变 第一百一十三章 实体的通用标签 下 在java版中,怎样制作出一个真正的浮空字? 这就要联系到minecraft中有哪些东西可以产生浮空字了。 在本书第二章介绍命令方块时,有提到虽然命令方块可以产生浮空字,但你并不指望能拿这东西做浮空字。 因为以下两个原因: 1.浮空字是一直显示的,但是命令方块的浮空字只能在你指向那个命令方块时才能出现。 2.浮空字就是浮空字,没有显示出额外的东西。但是命令方块它本身就是一个方块,无法变成透明的(除非你用了材质包)。 那是否有其他方法? 当你给一个实体命名,然后指针指向这实体,就会看到实体的名字以浮空字的形式显示了出来。 但这个浮空字仍然不能拿来用,因为它只能在指针指向实体的时候才出现。 那么真的就没有办法了吗? 别忘记了,玩家也是实体,名字也是浮空的,但它就是不会消失。 这是为什么? 就是因为『customnamevisible』这个标签。 customnamevisible标签的数据类型是byte字节型(整型中的一种),值是一个布尔值。当为0(false)的时候,这个实体的自定义名字就只能在你指向这个实体的时候出现;当为1(true)的时候,这个名字就会一直显示了! 所以说,只要生成一个customnamevisible为1的盔甲架,就可以制作浮空字了?比如: \/summon armor_stand ~~~{customnamevisible:1} wow,生成出来了一个头上悬浮着『盔甲架』的盔甲架! 没错!浮空字就是这么制作的! 但好像还少了些什么......如何自定义浮空字的内容呢?这个浮空字为什么会掉下来呢?盔甲架怎么隐藏呢?况且这个浮空字打几下就没了。 为了解决这三个问题,我们需要继续了解实体的通用nbt。 自定义浮空字内容很简单,我们有两种办法: 1使用命名牌给盔甲架命名 2使用nbt 实体nbt中的customname标签的数据类型是文本『string字符串』,用于储存这个实体的自定义名称。比如: \/summon armor_stand ~~~{customname:“explodingtnt“,customnamevisible:1} \\\\适用于java1.13以下版本\\\\ \/summon armor_stand ~~~{customname:“\\“explodingtnt\\““,customnamevisible:1} \\\\适用于java1.13及以上版本\\\\ 这就可以生成一个一直显示着『explodingtnt』的盔甲架。需要注意,对于java1.13及以上版本来说,customname的值需要使用json文本。 防止浮空字掉下来很简单,把实体的『nogravity』设置为1就行了嘛。 nogravity标签的数据类型是byte字节型,它控制着实体是否能够运动。如果为0(false),那么实体怎么奔放都可以。如果为1,那么motion就会失效(虽然仍然在奔放),也就是这个实体它失去了速度。 用通俗易懂的语言来讲,就是组成这个实体的原子,已经完全没有了能量。我们由此可以得出一个结论: 一个nogravity为1的实体,它的温度是绝对零度(滑稽)。 将这个实体的温度降到绝对零度之后,我们就要开始对它的防御动手,让它变成一个永远无法被生存、冒险玩家击败的实体(创造模式玩家除外)。 关系到这个实体是否无敌的标签是invulnerable(数据类型也是byte字节型)。一般的实体invulnerable为0,如果设为1,那么你就别想不使用作弊并在生存模式中去击败它了。 现在,我们这个浮空字基本上是完工......等等,我们还没把盔甲架隐藏呢! 怎么使得一个实体隐藏呢?使用隐身药水吗?或是一个能够使得实体隐形的nbt? 最好是有一个实体通用nbt标签能够有让实体隐形的效果,可惜的是,并没有。 但这不代表盔甲架没有。让我们回忆一下第九十六章番外的内容: 『invisible——如果指定这个标签的值为1,在指令执行成功后如果你发现盔甲架似乎并没有生成,并不是出了bug,而是盔甲架处于隐形状态(浮空字就是用这东西做出来的)』 唉,这不就有了吗,让我们试一试: \/summon armor_stand ~~~{invisible:1,invulnerable:1,nogravity:1,customname:“\\“explodingtnt\\““,customnamevisible:1} \\\\适用于java1.13及以上版本\\\\ 这会召唤一个『隐形的、无敌的、不会移动的、叫做「explodingtnt」的、一直显示实体名称的』盔甲架。没错!这就是浮空字! 现在这个浮空字已经真正浮空了。如果你有兴趣去看它的nbt,就会发现其中有一个onground标签,其值为0b。 这个标签是干啥的呢?就是用来检测实体有没有接触地面,接触了为1(true),没接触为0(false)。 到这实体的通用标签已经快完了,只剩下一点点: silent——这个实体是否会发出声音 glowing——这个实体会不会发光 tags——实体的记分板标签数据 hasvisualfire——实体是否看起来处于着火状态 silent标签的数据类型为byte字节型,值为1则实体不会发出声音,为0则会发出声音。 glowing标签数据类型也是byte字节型,但它的作用看起来有点奇怪——实体会发光? 如果你不是一位jvav玩家,那你一定知道minecraft有一个叫作『光灵箭』的东西。当光灵箭射中一个实体时,那个实体就会发光一阵,而且隔着墙壁都可以看到。 实体为什么会发光呢?除了实体被附上了『发光』效果之外,就是这个glowing标签在起作用。当glowing标签为1时,实体就会发光,为0则不会。 hasvisualfire标签的数据类型也是byte字节型,值为布尔值。当它的值为1时,实体就会“燃起来”,但不会真的受到伤害。 tags标签的数据类型为文本列表(string字符串列表),用来储存该实体所拥有的记分板标签。比如: \/summon armor_stand ~~~{tags:[“a“,“b“]} 这将会生成一个带有标签『a』和『b』的盔甲架。 本章到此为止。 第一百一十四章 死亡的玩家到底是不是个实体? ok,在断更了一周多之久后,作者我又回来啦! 首先先给正在参加高考(没错今天高考,不会有人不知道吧?不会吧?)的各位送上一个祝福。 然后估计大家看了这么多章nbt后头有些疼吧?那么接下来我们做一个中场休息,开一个新的第十二卷:中场休息。 实际上作者比你们更头疼,毕竟nbt这东西,五分靠记忆一分靠minecraft wiki。 那么剩下四分呢?全靠理解力! 接着就该进入今天的正题了:死亡的玩家到底是不是个实体? 我们知道,一个游戏中的玩家,他和你一样,有两种形态:活着和死了。 你死了,那就真死了,但就算你死了,起码你还是一团物质,有质量。 那么mc里的玩家死了会变成什么呢? 现实中一个人是一坨物质,死了,也是一坨物质。 mc里的玩家是一坨实体,死了,是不是也是一个实体呢? 为了了解这个问题,并把“?”拉直成“!”(等等,你这是???),我们需要找到游戏的外部文件,然后....... 呃,其实不用这样的,我们可以直接从目标选择器入手,因为通过目标选择器,可以锁定目标玩家。 @s、@r、@a、@p都是用来锁定目标玩家的,而其中的@a可以锁定全部玩家。 接下来这个问题就来了,这个锁定全部玩家,是指锁定全部活着的玩家,还是全部的玩家? 肯定是后者,不然为什么mojang为什么是写“全部玩家”而不是写“全部活着的玩家”呢? 当然过早下结论是不行的,还是得要实验的。 具体的实验过程(有兴趣的可以自己做一做): 1.开启我亲爱的基岩版 2.创建一个新的存档 3.创建一个新的名为“测试”的计分项,并把它显示在侧边栏 4.获得并放置一个一直重复执行的命令方块,并写上\/scoreboard yers add @a 测试 1 5.将模式调到生存 6.输入\/kill,同时观察侧边栏的值有没有停止增加 结果应证了我们的猜想:@a包含死亡的玩家。 但这仍然无法回答我们的问题:死亡的玩家到底是不是个实体? 为何呢? 因为@a是“全部玩家”,而@e才是“全部实体”啊! 如果@e包含死亡的玩家,那么死亡的玩家是实体,如果没有,那就不是实体。 那么使用@e怎么才能变成类似@a的效果呢? 很久以前就说过了,是@e[type =yers] 接着实验继续: 7.将模式再一次调回创造 8.将命令方块内的\/scoreboard yers add @a 测试 1改成\/scoreboard yers add @e[type =yers]测试 1 9.再一次将模式调回生存 10.输入\/kill,同时观察侧边栏的值有没有停止增加 你猜结果怎么着? 当死亡的那一刻,侧边栏的值就停止增加了! 这说明了什么呢? 死亡状态的玩家,他根本就不!是!一!个!实!体! 虽然你可以使用@a检测到他,但你无法用@e[type =yer]检测到他! 但得出了这个结论,我们也就同时得出了另一个结论: 在minecraft中,处于死亡状态的生物他不是一个实体! 这就可以说明为什么死亡的生物会雪~花~飘~飘~(北~风~啸~啸~,天地~一片~苍~茫~~~~~)变成一个粒子效果然后消逝。 那么这个冷知识到底有什么用呢? 我们知道@a包括全部玩家,@e[type =yers]包括除死亡玩家外的所有玩家,那么我们就可以得出一个公式: @a -@e[type =yer]=@die(@die指死亡玩家) 也就是说可以用@a和@e[type =yer]这两个的差来检测死亡玩家。 但如果要检测单个玩家的死亡呢? 建议提出这种问题的人重读一下小学,看看上面这个公式是什么运算? 减法! 既然是减法,你当然可以通过“两个减数同时加上或减去相同的数,差不变”的减法性质,来对@a和@e同时添加相同的额外条件,让结果不变,而同时又实现别的功能,比如同时添加一个计分项值判定,就可以判断单个玩家了是不是?这样子,你就可以在基岩版做出一个死亡榜了! 而上面这段话也同时证明:虽然mc不归牛顿管,但还是归阿基米德管的嘛。 所以理科要学好啊,不然你连一个游戏都玩不好啊。 嘿,那位,别暂停了,继续放。 一~剪寒梅~~傲立雪中~~ 只为~伊人~飘~香~~~~ 爱~我所爱~~无怨无悔~~ 此情~长留~心~间~~~~ ........ 完蛋被一剪梅洗脑了 第一百一十五章 websocket在minecraft里的用处 在第八十五章的时候,作者提到了下面这些指令: \/wsserver \/connect \/enableencryption 这些指令估计你现在都忘记是做什么用的了,那么先来回顾一下: “........用于连接websocket服务器.......“ 那么websocket又是什么东西呢? 第八十五章其实讲得已经很清楚了,就是用来上网的。 只不过这个上网是终端执行指令的上网,通过传输文本来让你知道你到底在那网站上干了啥。 可是这些指令又有什么作用呢? 通过一波企业级理解后,我们并没有得出答案,但得出了另一个结论:这三个指令,代表着mojang对传统浏览器的一次宣战,破天荒地使用了游戏形式来加强了浏览器的可玩性,并抛弃了传统的搜索引擎,只保留了输入服务器ip的空。从这个角度来看,我们可以发现minecraft它不仅仅是一款游戏,还是一个websocket浏览器! 算了不瞎扯了,我们回归正题:可是这些指令又有什么作用呢? 是有作用的。但作用不是在这个指令本身,而是在那些websocket服务器上。 你可以通过这些指令,来连接到其他minecraft玩家创建的可以与minecraft连接的websocket服务器,并通过这些服务器,来达成原版mc做不到的事情。 比如作者前几个月看到过一个视频,只不过作者把它丢到收藏夹吃灰去了,现在作者又重新找到了这个视频,并拍了拍上面的灰,然后你就可以看到这些指令能做什么用了: 连接过后,服务器就可以和你的minecraft搭建一个websocket桥梁,然后玩家可以在聊天框发送不带“\/“的信息,服务器可以读取到这些信息,并上传到云端处理,然后将结果通过websocket搭建的桥梁返回到单人的minecraft游戏中。 看起来是不是很厉害?实际上,的确是很厉害,比指令还要厉害。 为何?我们先不说生成一个巨大的照片,单单是这个读取玩家发送的聊天消息,你能只用指令做到吗?别说你了,作者也做不到。 那么websocket这么厉害,该怎么做出来呢? 很“简单“,首先,你需要有一个服务器。 然后,你要学会一些代码。 接着,你要学会websocket。 你还可以进入基岩版测试一下,如果成功,那么恭喜你!你成功了! 只不过这还只是最基础的,随着服务器的扩大,你可能还需要加入更多的东西,比如网站、qq群、qqai等,服务器也需要扩容,而且也要小心他人宣传。 这个时候你可能会说:“他人宣传不是挺好的吗?为什么要小心呢?” 还记得几百字前的那个websocket服务器吧?一经那位up的宣传(可能还有更多),服务器就需要扩容了。 毕竟,这些都是钱啊!做这些的基本上都是亏的,而且很多是净亏,全靠那些开发的人的工资支撑。所以如果有一天你发现你的websocket服务器爆满了,那么请你小心你的钱包,不要让本来就扁的钱包变得更扁了啊! 第一百一十六章 advancement-让人一夜回到解放前的指令 2017年6月7日,mojang发布了一次minecraft java重大更新,即minecraft java1.12版本,又称“多彩世界更新”。在这次更新中,许多的方块和物品都迎来了“多彩时代”,然而,在其他方面的一些更新也是值得注意的。 其中,最需要注意的就是成就系统被进度系统取代了。同时随着进度取代成就的,还有一个全新的指令:\/advancement 这是什么指令呢? 首先我们看看它的中文翻译:进度 看看它的中文翻译,这已经满脸都写着“进度”二字了。那么它到底有什么用? 很简单,修改一个玩家的进度。 没错,使用这条指令,你可以开局1秒不到就“结束了”,也可以在别人终于达成“就快到了”进度时,突然给它移除掉这个进度。 只不过我并不推荐你这么做,因为如果这样子做的话他会疯的(实际上并不只是“疯”那么简单,小心他会给你来个当场自杀,因为这可比删别人玩了10年的存档还要狠得多个亿古戈尔)。 那么具体就来看看这条指令到底该怎么用吧。 \/advancement 作用:对指定玩家进行移除或添加指定进度的操作。 使用权限下限:管理员(op) 是否可使用命令方块执行:是 格式: \/advancement <目标选择器:玩家> only <进度id>[条件] \/advancement <目标选择器:玩家><进度id> \/advancement <目标选择器:玩家> everything 首先,你需要选择你要进行哪种操作,即到底是grant(授予)还是revoke(移除)。 然后你就需要通过目标选择器来锁定你要操作哪个玩家。 接着,就有点不一样了。 第一个格式这里是only,中文即“只有”,也就是你只有操作玩家的这个进度。 第二个格式就多得很了,你可以选择是until(直到.....为止)或是from(从)还是through(从头到尾)的操作。人工翻译成人话就是: until——从这条进度类别的起始进度开始,直到这条进度的所有进度。 from——从这条进度开始,下游的所有进度。 through——从这条进度类别的起始进度开始,通过这条进度,直到这条进度下游的所有进度。 那么知道了这三个操作的作用,那么具体是锁定哪些进度呢? 比如下界里的“凋零山庄”这个进度,它的上游是: 下界(起始进度)——>可怕的要塞——>诡异又可怕的骷髅——>凋零山庄(1.12版本) 它的下游是: 凋零山庄——>带信标回家——>信标工程师(1.12版本) 那么用only操作的话,那么只会操作“凋零山庄”这个进度。 而用until操作,则会操作“下界(起始进度)——>可怕的要塞——>诡异又可怕的骷髅——>凋零山庄”这一整条的所有进度。 用from,则会操作“凋零山庄——>带信标回家——>信标工程师”这一整条的所有进度。 用through,则会操作“下界(起始进度)——>可怕的要塞——>诡异又可怕的骷髅——>凋零山庄——>带信标回家——>信标工程师”这一整条的所有进度。 那么问题来了,有些进度的下游它还有分支啊,那么这些分支该怎么办? 很简单,全选呗。 比如minecraft里的“冰桶挑战”这个进度,它的下游是: (假装这里是空格空格空格空格空)?僵尸科医生 冰桶挑战——>我们需要再深入些——>隔墙有眼——>结束了?(1.12版本) 那么使用from就会选择上面的所有进度。through同理。 那么搞懂了这3个之后,最后的everything是什么呢? 锁定全部成就啊! 也就是说,使用\/advancement @s everything就可以在一秒内给予自己所有的成就或移除自己所有的成就喽。 这真的是太棒了! 第三段格式到此为止了,接下来我们看看“再接着”:进度id 进度id的格式和我们的文件夹路径的格式基本是一样的。minecraft这台电脑有5个盘,分别是:story(minecraft)her(下界)、end(末地)、adventure(冒险) 所以进度的id的最开始都是这五种。 然而接下来就比较没有规律了,因为第二层就是进度id了。 比如“热腾腾的”这个进度的id就是:story\va_bucket(注:其实这也是有命名空间的:minecraft:story\va_bucket,所以其他mod才有进度)。其va_bucket直译成中文就是:熔岩桶。 但其实这也可以理解的,因为本身一个类别就没有多少进度,再细分那能够分吗? 那么第二个格式也就到此为止了,我们可以根据“热腾腾的”举一些例子: 1.\/advancement grant @s until story\va_bucket——给自己达成“热腾腾的”、“来硬的”、“获得升级”、“石器时代”、“minecraft”进度。 2.\/advancement grant @a from story\va_bucket——给所有人达成“热腾腾的”、“冰桶挑战”、“我们需要再深入些”、“隔墙有眼”、“僵尸科医生”、“结束了?”进度。 3.\/advancement grant @a through story\va_bucket——给所有人达成“minecraft”、“石器时代”、“获得升级”、“来硬的”、“热腾腾的”、“冰桶挑战”、“我们需要再深入些”、“隔墙有眼”、“僵尸科医生”、“结束了?”进度。 但你估计也发现了,第一个格式还没到此为止。 因为在第一个格式的最后,还有一个非必填项:[条件]。 这是什么意思呢? 这就要联系到进度的json文件存储格式了。 所以条件我们就再拖....哦不是下次再讲了。 (嘿,作者,那个“就快到了”成就的id是什么?) (不是之前就说了吗?是adventure\/almost_there,你自己到九十五章到九十六章间的minecraft2020愚人节更新介绍看,翻到最后有。) 进度id大全: -minecraft minecraft——story\/root 石器时代——story\/mine_stone 获得升级——story\/upgrade_tools 来硬的——story\/smelt_iron 整装上阵——story\/obtain_armor 热腾腾的——story\va_bucket 这不是铁镐么——story\/iron_tools 不吃这套,谢谢——story\/deflect_arrow 冰桶挑战——story\/form_obsidian 钻石!——story\/mine_diamond 勇往直下——story\/enter_theher 钻石护体——story\/shiny_gear 附魔师——story\/enchant_item 僵尸科医生——story\/cure_zombie_viger 隔墙有眼——story\/follow_ender_eye 结束了?——story\/enter_the_end -下界 下界—her\/root 见鬼去吧—her\/return_to_sender 光辉岁月—her\/find_bastion 深藏不露—her\/obtain_ancient_debris 曲速泡—her\/fast_travel 阴森的要塞—her\/find_fortress 谁在切洋葱?—her\/obtain_crying_obsidian 金光闪闪—her\/distract_piglin 画船添足—her\/ride_strider 脆弱的同盟—her\/uneasy_alliance 战猪—her\/loot_bastion 天涯共此石—her\/use_lodestone 残骸裹身—her\herite_armor 惊悚恐怖骷髅头—her\/get_wither_skull 与火共舞—her\/obtain_ze_rod 锚没有九条命—her\/charge_respawn_anchor 热门景点—her\/exploreher 凋零山庄—her\/summon_wither 本地的酿造厂—her\/brew_potion 带信标回家—her\/create_beacon 狂乱的鸡尾酒—her\/all_potions 信标工程师—her\/create_full_beacon 为什么会变成这样呢?—her\/all_effects -末地 末地——end\/root 解放末地——end\/kill_dragon 下一世代——end\/dragon_egg 远程折跃——end\/enter_end_gateway 结束了…再一次…——end\/respawn_dragon 你需要来点薄荷糖——end\/dragon_breath 在游戏尽头的城市——end\/find_end_city 天空即为极限——end\/elytra 这上面的风景不错——end\/levitate -冒险 冒险——adventure\/root 自我放逐——adventure\/voluntary_exile 怪物猎人——adventure\/kill_a_mob 成交!——adventure\/trade 胶着状态——adventure\/honey_block_slide 扣下悬刀——adventure\/ol_betsy 甜蜜的梦——adventure\/sleep_in_bed 村庄英雄——adventure\/hero_of_the_vige 抖包袱——adventure\/throw_trident 瞄准目标——adventure\/shoot_arrow 资深怪物猎人——adventure\/kill_all_mobs 超越生死——adventure\/totem_of_undying 招募援兵——adventure\/summon_iron_golem 一箭双雕——adventure\/two_birds_one_arrow 现在谁才是掠夺者?——adventure\/whos_the_piger_now 劲弩手——adventure\/arbalistic 探索的时光——adventure\/adventuring_time 魔女审判——adventure\/very_very_frightening 狙击手的对决——adventure\/sniper_duel 正中靶心——adventure\/bullseye -农牧业 农牧业——husbandry\/root 与蜂共舞——husbandry\/safely_harvest_honey 我从哪儿来?——husbandry\/breed_an_animal 永恒的伙伴——husbandry\/tame_an_animal 腥味十足的生意——husbandry\/fishy_business 举巢搬迁——husbandry\/silk_touch_nest 开荒垦地——husbandry\/nt_seed 成双成对——husbandry\/bred_all_animals 百猫全书——husbandry\/plete_catalogue 战术性钓鱼——husbandry\/tactical_fishing 均衡饮食——husbandry\/bnced_diet 终极奉献——husbandry\/obtainherite_hoe \/advancement历史: java版 1.12——17w13a——加入了\/advancement命令 第一百一十七章 控制成就系统的指令 上一章我们提到了进度系统,也提到了修改进度的指令:\/advancement。 那么在java1.12版本之前,也就是成就还未移除的时候,那个时候的玩家它们该怎样通过指令获得或移除成就呢? 在java beta1.5版本,成就系统正式加入到了minecraft,尽管在当时成就系统的功能并不完善。 但直到1.7.2版本更新之前,成就系统仍然跟指令没有任何关系。也就是说,在当时,成就系统是一个独立的系统。 1.7.2版本更新,这个独立的系统被打破了。 1.7.2 13w36a更新,更新了成就系统,且将成就系统和指令系统第一次进行连接。其中,除了成就和计分板连上了关系,mojang还对成就添加了一个新的指令:\/achievement。 这是什么指令?和\/advancement。差不多,是可以控制指定玩家成就的指令。 那么具体就来看看这条指令到底该怎么用吧。 \/achievement 作用:对指定玩家进行赋予或移除成就的操作。 使用权限下限:管理员(op) 是否可使用命令方块执行:是 格式: \/achievement <成就id|*>[目标选择器:玩家] 首先和\/advancement一样,是选择give(赋予)还是take(移除)的操作。 然后就不一样了,因为这里直接就上成就id了。 等等,那个“*”是干啥用的? 全选啊!所以\/achievement give *@s就可以让你一秒钟获得全部成就了。 只不过不填目标选择器也行,因为目标选择器是非必填项,不填默认是执行者自己,填了就是指定玩家了。 但是,如果填成就id,是不是和\/advancement一样,只获得这个成就呢? 其实不然,比如直接使用\/achievement达成“获得升级”成就,那么你不会只获得这个成就,还会获得上游的全部成就,也就是: “打开物品栏——>获得木头——>制作工作台——>采矿时间到——>获得升级”这一连串的成就,即\/advancement的until操作效果。而如果按照看\/advancement的眼光来看\/achievement,那么\/achievement只有until和everything的操作。 那么问题来了,成就id到底有哪些呢? 在minecraft wiki里有对成就id的格式有简单说明: achievement.成就名(其中“成就名”为有效的成就标识符) 但如果我们找到“成就”这个词条,只会出现基岩版的成就。在这里有包括成就图标、成就名(中文)、游戏内描述、实际需求(若异)、xbox点数以及奖杯(ps),可偏偏就是没有成就标识符。 而在成就\/java版词条就更寒酸了,就几张图片和历史,完全就把java版的成就当成空气一样看待。 而唯二的成就id就只有在\/achievement词条里有:achievement.overkill(赶尽杀绝)和achievement.openinventory(打开物品栏)。 其他的成就id就像notch的离开mojang一样也离开了minecraft,在minecraft wiki连个影子都看不到。 真的是这样吗? 别忘了,上面这些词条都是进过中文翻译的,而mojang经常使用英文来作为一个方块或物品的id,那么我们或许可以不要转换语言? 但令人震惊的是,minecraft wiki的语言竟然转换不回去!那么该怎么办呢? 看来,minecraft wiki也并不怎么全面啊,所以我们要把目光移向别的地方。 2016年8月29日,在minecraft java版1.11.2都还未更新时,百度用户steven8967将minecraft 中文wiki的“成就”词条全部复制到了百度百科下“成就”词条中的一个义项。令人震惊的是,这个已经创建了将近4年的词条,浏览量竟然不过万!所以,直到现在,这个词条义项的内容并没有发生过多大改变,它完好无损地保留了2016年8月29日的minecraft 中文wiki词条的内容!在其中我们发现,这个列表不止有现在minecraft 中文wiki成就词条的大部分内容,还包括了ps的奖杯类型和java版的成就id! 通过这个词条,我们成功获得了minecraft java的所有成就id(百度百科牛逼!): 打开物品栏——openinventory 获得木头——minewood 这是?工作台!——buildworkbench 采矿时间到!——buildpickaxe “热”门话题——buildfurnace 来硬的——acquireiron 耕种时间到!——buildhoe 烤面包——makebread 蛋糕是个谎言——bakecake 获得升级——buildbetterpickaxe 美味的鱼儿——cookfish 在铁路上——onarail 出击时间到!——buildsword 怪物猎人——killenemy 斗牛士——killcow 当猪飞的时候!——flypig 狙击手的对决——snipeskeleton 钻石!——diamonds 我们需要再深入些(前往下界)——portal 见鬼去吧!——ghast 与火共舞——zerod 本地的酿造厂——potion 结束了?——theend 结束了。——theend2 附魔师——enchantments 赶尽杀绝——overkill 图书管理员——bookcase 探索的时光——exploreallbiomes 开始了?——spawnwither 开始了。——killwither 信标工程师——fullbeacon 种群恢复——breedcow 给你钻石!——diamondstoyou 君临天下——overpowered 所有工具——? 兽群领袖——? 获得所有奖杯——? 猪排——? the haggler——? 盆栽种植——? 铁肚皮——? 在寒冷中——? 一满箱的圆石——? 可再生能源——? 爱听的话——? 保镖——? 钢铁侠——? 僵尸医生——? 驯狮者——? 弓箭手——? 扎染服装——? 蹦床——? 伪装——? 地图之屋——? 货运站——? 闻到的一切!——? 以其人之道治其人之身——? 好吧,并不是全部,但也已经不少了。 不得不说,老版本的成就,在我看来,比新版本的进度还要好。 \/achievement的历史 java版 1.7.2——13w36a——加入了\/achievement命令。 1.9——16w03a——\/achievement命令不再影响统计数据。 1.12——17w13a——移除了\/achievement命令。 java版成就系统的历史 java(beta) 1.4——测试版的成就系统可在源代码中找到,亦出现于notch发布的测试视频中。其中有打开物品栏、采集木头和制作工作台。 1.5——加入了成就系统。实际上开始是想在beta 1.4加入成就系统,不过那时功能还不完善。首个被notch确认的成就是当猪飞的时候,尽管比起实际需求这名字有点夸张了。 1.8——2011年7月13日 notch推特了关于增加狙击手的对决成就。 java版 1.0.0——beta 1.9 prerelease 6——“结束了。”成就的图标被改变。 1.5——13w04a——下载升级minecraft不会再重置成就了。 1.7.2——13w36a——更新了成就系统,现在在各个世界\/服务器中单独计算成就。同时增加了更多成就:探索的时光、开始了?、开始了。、信标工程师以及种群恢复,但是探索的时光成就无法获取。并且成就现在可以作为计分板系统的对象了。 1.7.2——13w37a——“采矿时间到!”、“耕种时间到!”和“出击时间到”现在用木板之外的材料合成也可以得到了。同样“获得升级”现在也可以通过用任何木头以外的材料合成镐获得了,之前需要用圆石合成。如果你第一次合成的镐就不是木质的,那你将同时得到“采矿时间到!”和“获得升级”两个成就。 1.7.2——13w38a——加入了成就“给你钻石!”。同时“钻石!”的图标从被改变。之前的图标被“给你钻石!”成就使用了。 1.7.2——13w39b——“给你钻石!”可以通过扔给一个僵尸获得了,这样单人模式也可以获得这个成就了。 1.8——14w06a——加入了成就“君临天下”。 1.8——14w17a——“探索的时光”现在不用命令也可以获得了。之前,指定的38个生物群系必须在到访其他生物群系前到访过,而为了得到前提成就“结束了?”必须到达末地。现在“不能到达过其他生物群系”的限定被移除了。同时获得“探索的时光”成就不再需要到过冻洋和悬崖这两个从13w36a后不再生成的生物群系。 1.8——14w32a——更正了“斩尽杀绝”成就的描述,你必须制造一击9颗心的伤害——之前描述是8颗心。 1.9——15w44a——移除了附魔金苹果的合成配方,使“君临天下”成就无法获得。 1.9——15w45a——“君临天下”成就的简介和要求从“制造一个附魔金苹果”变成“吃掉一个附魔金苹果”。 1.12——17w13a——移除了成就,取而代之的是进度。 第一百一十八章 ability-怎样禁言一个人 在qq群里、论坛里、游戏里,凡是带有很强的交流性质的软件,几乎都有“禁言”的惩罚项目。那么在minecraft,也可以把一个人禁言吗? 很明显,在那些大型服务器里是可以的,小型的服务器没这么多精力搞那么多处罚标准,直接就把本来要禁言的人给封了。 那如果是原版呢? java版目前是没有的,单机游戏禁什么言,难不成我禁言我自己?所以mojang没搞(多人游戏例外,有黑名单和白名单)。那么基岩版呢? 很明显,基岩版的开发团队没想那么多,单人多人游戏统一没有禁言,连个拉黑的指令都没有(网易版例外,只不过网易版就比基岩甚至java版狠多了)。 既然java版和基岩版都没有,那么教育版呢? 有! 在教育版,有这么一条指令:\/ability 这条指令的作用很简单:赋予或剥夺某一个玩家的能力(游戏内描述:设置一名玩家的能力),能力无非就是这么几个: 1.worldbuilder——成为世界建造者的能力 2.mayfly——能飞行的能力 3.mute——不能发言的能力(这.....) 然后就是一个true和false的布尔值选项。等等,格式还没上哦: \/ability <目标选择器:玩家><能力:能力id><值:布尔值> \/ability <目标选择器:玩家>[能力:能力id] 第一个格式就是上面说的,那么第二个呢? 很简单,如果不填能力id,那么你将知道你可以填什么能力。 呃.....这个作用........ 那么填了呢? 比如输入: \/ability @s mute 回车你会发现你get到了你的mute是处于false状态,也就是你没有不能发言的能力。 当然这个能力估计大家都不想要。 所以你同时也知道了mute默认是false状态。 那么调成true会怎么样呢? 输入: \/ability @s mute true 你会获得一条信息: “已赋予你''mute''技能,技能已更新” (懂了,原来不能说话也是一个技能,这就去和服主对线) (别去,你说不了话) 现在,你已经获得了mute权限,恭喜你。 然后你可以尝试发一下言。 发完言后,你就会获得一个黄色通知:聊天当前被禁用。 等等,还有\/w、\/me等指令可以用呢! 实际上这些命令都不能用了。 当然啦,除了聊天类其他指令都可以用的。 所以,如果你在一个基岩版服务器里(需开启教育版)禁言一个乱骂别人的xxs,那么你就可以畅所欲言了,你说的话他都看得见,当然肯定其中会混杂着一些黄色的字体:聊天当前被禁用。他看到那一连串的黄色字体肯定会更加的暴躁,但他就是发不了言,最后只能悻悻退出服务器。(哇想想那画面都觉得很喜感) 接下来我们再来看看剩下两个能力: worldbuilder——成为世界建造者的能力 mayfly——能飞行的能力 第一个:worldbuilder。 这个能力默认是false,即便是创造也是false,生存就更不用说了。那开了呢? 很抱歉,作者实在找不到开了和关了有什么区别,这个就留你们去找了。 那么最后一个:mayfly 在生存和冒险,这肯定是关的,创造肯定是开的。 那么创造模式把这个关掉会怎么样? 妈妈你快看,哎嘿那个服主他就是飞不起来,哎嘿他摔下去了,哎嘿他......哦他创造不会死。 然后在生存把这个开起来?! 夭寿啦,生存玩家竟然飞起来啦,我的天! 哦不!他摔死了! 天,看看那个服主,硬是追了一天一夜也没有追到那个开生存的,连个影儿都没摸着,真可怜。 这画面,想想就很喜感,要是真的出现...... 不要笑挑战来一个? 第一百一十九章 称号系统 作者忽然发现\/team好像少讲了一些modify(或者说这是最近更新的),那么今天我们就来补全以下这个漏洞。 而这3个modify,竟然都是关于队伍的显示名称的。 这说明什么?我们原版服务器再也不需要称号mod了! (实际上这一章的内容灵感是qq群的一位玩家想搞称号系统,可就是搞不出来) 当然,在开始前,我们要搞清楚哪些版本可以用这三个。 仔细一看,哦,这不是1.13就更新了吗?当时team从记分板里独立出来时就添加了,不信你看: java版 1.13——17w45a——加入了\/team。 1.13——18w20a——加入了\/team option <队伍> prefix <前缀>和\/team option <队伍> suffix <后缀>。 1.13——pre8——\/team option被更改为\/team modify,同时加入了\/team modify <显示名> disyname,并修改了队伍名称的格式,现在是文本组件,而不是原始字符串。 也就是说,1.13以下的服务器还是乖乖的去用mod吧,或者去升级一下服务器版本,只不过可能会出现某些特性。要不就删档升级重来,解决一切的问题。 说了这么多,那么这三个到底是什么呢? 历史里就有了,分别是: disyname——队伍显示名称 prefix——队伍玩家聊天时显示名称的前缀 suffix——队伍玩家聊天时显示名称的后缀 这三个的格式都是: \/team modify <队伍id> 而json文本,你就可以大胆的写一些东西了,比如你可以弄一个红色的“[生存带师]”称号,把它放在一个玩家名称的前面: \/team modify 称号生存带师 prefix {“text“:“[生存带师]“,“color“:“red“} 然后把这名玩家神不知鬼不觉地添加进这个队伍,接着这名玩家说了一句“谁有铁,能不能借我一点?”。 其他玩家看到的这句话就变成了这样: <[生存带师]lbwnb>谁有铁,能不能借我一点? 当然这还只是初级的,更高级的还可以加上这名玩家的等级! 怎么弄呢? 很简单,首先你弄一个计分项来跟踪玩家的xp经验等级,也就是: \/scoreboard objectives add 等级 level 然后你修改上面的指令变成: \/team modify 称号生存带师 prefix [{“text“:“[lv.“,“color“:“red“},{“score“:{“name“:“*“,“objective“:“等级“}},{“text“:“]“,“color“:“red“},{“text“:“[生存带师]“,“color“:“red“}] 那么当那名玩家再次发言,他的发言在别人看来就是: <[lv.1][生存带师]lbwnb>谁有铁啊!!!我真的很缺铁哎!!!> 如果你学会了json,你还可以把称号搞出更多的花样,比如把鼠标放上去就可以显示这名玩家的详细信息之类的(真的,理论上这真的可以做到,比如说上面这条指令就是理论上可以做到的),甚至还可以搞出点一下这名玩家的称号就传送到这名玩家之类的。 至于基岩版嘛......就算没钱也可以去搞一个html——不对是hmcl启动器嘛,免费的,qq群里就有。 如果真的搞不到........ ssic.minecraft——正版网游minecraft值得你去体验,支持在线联机等有趣功能,妈妈再也不愁我玩不了minecraft了! 第一百二十章 区块加载器 在第九十七章,作者讲到了java版可以使用forceload指令来创建一个常加载区块。 但那个指令是在1.13.1版本添加的啊! 可是现在大部分人最常用的版本仍然是1.12.2,那么这些人该怎么办呢? 很简单,我们知道java版他本来就自带了一个常加载区块,也就是世界出生点区块。 把命令方块放在世界出生点区块内,就可以一直运行了。 那么怎样设置世界出生点呢? 额,在第三十四章不是讲过了吗,使用\/setworldspawn就可以在当前位置设置出生点了。 (教你一招,实际上你只需要输入一个\/set,然后按两次tab就可以了) 就这么简单。 但是如果要设置多个呢? 很抱歉,没有这个指令。 那么该怎么办呢? 这个时候我们就要引入一个新的概念:区块加载器。 什么是区块加载器? 这其实并不是一个指令。 也并不是一个方块。 那应该是什么? 红石机械啊! 没错,虽然这件事你不可能只用指令做到。但是你可以只用红石做到! 这说明什么?你的刷铁机有救了! 区块加载器根据实际用法大致有两个类别:加载当前区块的和加载指定区块的。 你可以在b站上搜到一大堆的视频教程,我相信你看完这些教程一定能做出来的。 (实际上有一个mod是专门解决这个问题的,如果不想要麻烦的话去下个mod也行) 我们可以在这里稍微了解一下这个技术的原理。 为了了解这个技术的原理,我们还要了解一下区块加载的原理: 当玩家从一个区块移动到另一个区块,玩家视距内的区块都会被加载,同时游戏会根据玩家现在的位置来加载一些新的区块,同时也卸载掉一些旧的区块,让游戏保持流畅。 但实际上,不只是玩家,红石、火焰以及漏斗都会加载区块。 那么这些区块什么时候会被卸载呢? 实际上不只是你,连你正在玩的minecraft都不知道。 但你正在玩的minecraft可比你要聪明一点,它知道它自己不知道该何时卸载掉这些区块,所以它想到了另一种方法:每隔45秒,它自己就会检查所有正在加载的区块,并标记那些玩家不在的那些区块,等待一个好的时机把它们卸载掉。 这就是区块加载的基本原理。 而区块加载器的原理就简单了,我们知道不仅是玩家,漏斗、火焰以及红石也会加载区块。所以我们只需要让那些机械不断的去加载区块,不就行了吗? 那么到底该怎么做呢? 别忘了,我们只知道区块加载的基本原理啊!我们还不知道那些漏斗什么的是怎么加载区块的。 其实很简单,我们拿漏斗举例。 假设,有一个漏斗在一个加载的区块边缘,它要漏的方向是对面没有加载的区块,而这个漏斗里面有一个物品。 然后这个漏斗就会尝试把这个物品给漏到对面的方块,但是对面是个还未加载的区块,它不知道它指向了什么方块。 于是它告诉游戏,让游戏加载这个区块。于是这个区块被加载了。 而这个漏斗终于发现它指向了一个锤子,漏不出来,所以它就完成了自己的使命。 这个时候你就成功加载了一个新的区块,而且不是玩家加载的。 而最简单的区块加载器,就是运用了这种原理,那么具体是怎么做的呢? 接着上文。这个漏斗完成了自己的使命,然鹅此时游戏发现:哎呀怎么新加载的区块还有一个装着物品的漏斗啊,于是游戏告诉这个新的漏斗,叫它赶紧漏。 然鹅这个漏斗发现不行啊,对面是未加载区块,咋漏,于是叫游戏加载这个新的区块。 加载好了,这个漏斗发现漏不了,就完成了自己的使命。而此时游戏又发现——卧槽怎么新加载的区块还有一个新的装着物品的漏斗。 于是又是漏,又加载,又漏,又加载,直到漏斗没有了。 但玩家肯定不想让游戏把这些区块给卸载,于是玩家们决定升级一下这个区块加载器,让其一直加载。 这时候,就要涉及到区块的卸载原理了。 区块的卸载有两种触发方式: 1.玩家远离区块那一刻 2.每45秒的检查 而不管是哪种触发方式,卸载的方法都相同: 1.游戏会将这些要卸载的区块都添加进一个表格,即哈希表。 2.游戏会按照哈希表的顺序来逐个卸载,然鹅这个顺序不一定是区块加载的顺序。 3.在每一刻的最后,游戏会进入区块卸载模式,但游戏每一次最多只能卸载100个区块,剩下的区块会等待下一次卸载。 这些险些被卸载的区块都还会正常运作,但游戏已经把它们贴在了卸载表上,相当于加上了一个死亡倒计时。 这些区块还有救吗?有救,只需要在下一次卸载之前,漏斗能提前加载那些区块,就可以将那个区块从卸载表上扯下来,让区块继续运作。 那么,我们就可以选择哈希表靠后的区块,我们就有机会它一直被漏斗加载。 没错,但是你该怎么知道哪个区块在哈希表靠后的地方? 其实哈希表的排序并不是随机的,而是有规律的。哈希表并不是单纯的一个表格,它是由哈希键索引的各种桶组合在一起的。而每一个区块的哈希键,由这个区块的x和z来决定。也就是说,每个区块的卸载顺序,由这个区块的x和z来决定。(注:一个区块的xz为这个区块的中心位置,即在f3调试界面区块坐标xz都为8的地方。 那么该怎么计算? 我们以世界原点(0,0)举个例子。 首先,游戏会将世界原点的x和z轴转换成2进制,然后组合在一起,变成一个长8字节的2进制数字。而每个字节由8个2进制数字组成,所以这个8字节的二进制数字,就长达64个位数。即: 0000000000000000000000000000000000000000000000000000000000000000 (实际上这就是典型的64位,即64个位数,这下子你应该知道了这个64和32位操作系统的区别了吧) 然后游戏就会把这串数字交给java处理。java首先会把这个数字分成两半,即: 00000000000000000000000000000000-00000000000000000000000000000000 (这其实有些像我们以前讲过的uuid) 接着java会把这串分成两半的数字左边跟右边做一次异或运算(即上面和下面的数字相同,输出0,不同,输出1),也就是: 00000000000000000000000000000000 00000000000000000000000000000000 得出来的结果是32位数: 00000000000000000000000000000000 你以为这就完了吗?其实还没完,java会再把这串数字分两半,再异或,即: 0000000000000000-0000000000000000(32位) —异或— 0000000000000000(16位) 然后把这个16位的二进制数字转化成10进制,即:0。 这就代表着这个区块的卸载顺序为0。 现在我们换一个坐标,换(3,3)吧: 3-3(10进制) —转2进制— 00000000000000000000000000000011-00000000000000000000000000000011 —异或— 0000000000000000-0000000000000000 —异或— 0000000000000000 —转10进制— 0 3,3坐标竟然还是0。 所以我们可以得出一个结论:由于对角线的坐标x和z的数字相同,导致异或后肯定为0,所以对角线的坐标在哈希表里的排序肯定为0。 紧接着,我们就可以通过这个结论,来反推出坐标里有一个数值为0的坐标(比如5,0)排序是最靠后的,数值为0的坐标即正东西南北方向。 而我们还可以通过上面的转化过程知道,转化的最大xz值不能超过,最小也不能小于-。 但是为了让大家更直观的了解区块加载顺序,作者就去计算了以原点为中心,16x16的区块的公式结果并制成了图片,最终结果可以加一下群看(群相册),不嫌麻烦的话....... 也可以前往这个网址查看:a1.qpic\/psc?\/v12hblhp1rg0d7\/ruamsa53pvqwn7flk88i5uzvblxld58ovynzzou1uuu8f0ryksv9jhy89sjob*octak2*rewhtk36coubewgwongptrer6ypkygr*zry!\/b&ek=1&kp=1&pt=0&bo=oaq4baaaaaabfza!&tl=3&vuin=&tm=&sce=60-2-2&rf=viewer_4(注意要加http) 这张图片区块颜色越红,结果数字越小,优先级越高;越白,结果数字越大,优先级越低。 而且如果深入研究,还是有很多规律的: 1.其实不难发现,这张图片只看颜色是对称的,而且上下对称,左右对称。 2.很明显就可以发现,这张图片看起来好像很复杂,其实是有层次的——第一层是每个区块(1x1),第二层是每4个区块(4x4),而更巧的是如果以4x4来看待这张图片,就会发现其实只有两种4x4的方形,只不过它们有些被镜像化了。 同时这张图片也证明了我们上面的说法:.....来反推出坐标里有一个数值为0的坐标(比如5,0)排序是最靠后的,数值为0的坐标即正东西南北方向。 说了这么多,区块的卸载顺序大致也搞懂了吧?但是此时又有一个新的问题出现了:如果一个“桶”里装了很多个区块,比如优先量都为0的区块全部装在一个桶里,这该怎么办? 其实也不需要太深究,这些已经够了。 接下来,让我们回到minecraft。了解了上面这些东西后,下面这些东西就已经很简单了。 我们知道每刻游戏最多卸载掉100个区块,那么我们就可以找100多个没用的优先级高的区块,比如全部找对角线的区块,让它们卸载了再加载,再卸载,不就可以了? 没错,这是一个很棒的想法,实际上区块加载器的原理也差不多就是这样。我们得一直运行100多个加载区块才能让特定区块保持加载。 别担心,这个工程只不过有点耗肝,脑袋配置较低稍微有点肝的话也能做得出来的。 (只不过除了肝,还有亿点耗铁) 大致方法已经敲定了,接下来就是细节了。 我们遇到的第一个问题就是:怎样让那些占哈希表的区块卸载了再加载,再卸载? 很简单,我们可以把旁边的区块也一起用上帮助加载。 我们以下面这个2x1的区块为一个例子: 0,16 你只需要准备两个漏斗和一些方块就可以搞定这个计算结果为0的区块。 参照上面的漏斗加载例子,你需要在0区块在对着16区块的边缘处放一个朝向16区块的漏斗,16区块那边也在对着0区块的边缘处放置一个对着0区块的漏斗,两个漏斗都放置一些物品。 那么这是怎么运作的呢? 假设你已经成功的按照上面的步骤制作出了100个常加载的0区块,那么你就会发现这个的运作原理是这样的: 1.在清除那一刻,0区块被卸载,而16区块继续运作,只不过被打上了死亡标签。 而下一刻,16区块的漏斗激活了0区块,0区块激活后其漏斗又把16区块给拉出了死亡表里。 45秒后,0区块又卸载,16区块漏斗又激活0区块,然后0区块漏斗又加载16区块,两区块又是这么平安无事。 就是这么个原理。 搞定了那100多个常被杀区块后,接下来你就可以来自由的设置你的常加载区块了。 (只不过处在对角线的要加载区块最好还是把里面的设施搬走吧,换一个区块) 假设你要不断加载相邻的4个区块(2x2)该怎么办? 在四个区块的交界处弄一个2x2的漏斗循环。 假设你要搞定相邻的两个区块该怎么办? 照着那100个常被杀区块那样做就行了。 假设你只需要弄好一个区块该怎么办? 很简单,其相邻的4个区块每一个都弄一个朝向该区块的漏斗。 这就是最简单的区块加载器做法。 (事实上还有更高级的维度加载器,通过维度加载器,可以同时加载两个三个甚至个维度,但那个装置更加的复杂) 但这些区块加载器仍然有被卸载的危险。 这个危险不是每45秒的卸载,而是玩家离开那一刻的区块卸载。如果玩家离开那一刻两个区块都同时被卸载。那就糟糕了。 (对了,按下f3+g可以打开区块调试界面,这个时候就可以看见区块的边界了,不再需要按f3一步一步试探) 现在,你已经知道怎么让多个区块同时加载了。如果你经常玩纯生存服务器,那么这个装置肯定会帮到你的自动化机器的,让其挂机也有收益。 只不过腐竹会不会找你算账那就不一定了。 第一百二十一章 json的格式 看来json不先讲完那是不行的,那么我们就先把json讲完吧。 json的格式相信大家在第二卷时就已经知道了个大概,即: {元素:值}(1.9版本以前) {“元素“:值}(1.9版本即以后) 其中,值可能是字符串、数字、布尔值等奇奇怪怪的东西,有些要加引号(比如字符串),有些不需要加引号。 但是其实json还带有另一种格式,这种格式它并不是用大括号包起来的,而是用中括号,即: [对元素:值](1.9版本以前) [“元素“:值](1.9版本以后) 你可能会问:哎这两种格式不是一模一样吗? 其实是不一样的,不一样的地方就在于前者有多个对象时只能: {“text“:“我的天淦***“,“color“:“red“} 或者是{“text“:“我的天“,“color“:“red“,“extra“:[{“text“:“淦“},{“text“:“***“}]} 而后者却可以这样子: [{“text“:“我的天“,“color“:“red“},“淦“,“***“] 或者是 [{“text“:“我的天“,“color“:“red“},{“text“:“淦“},{“text“:“***“}] 都可以达到上面大括号的效果。 这是为什么呢? 其实中括号就相当于把大括号里元素extra给独立出来一个格式,而extra就是一个json列表,这后面会讲到。 所以中括号虽然能把元素给拆分成一段一段的列表,但无法像大括号一样直接列出来,比如上面的: {“text“:“我的天“,“color“:“red“,“text“:“淦“,“text“:“***“} 如果把{}换成[]就不行了,就会报错。想让其不报错只能拆成一段一段的列表。 而且实际上json的全格式就是中括号,大括号格式只不过是从中括号里面拆出来的。 其实中括号这个格式没有你们想象的那么简单,注意到上面的中括号第一个例子中的“淦“和“***“了吗?它们并没有被加上“text“。 但他们确实就是text。 这是为什么?其实这就是一种偷懒的方法。 因为json最常用的就是text元素,所以json的作者就觉得这么多text看着太眼花缭乱。就简化了。 但是这种简化只能在中括号格式里用,大括号里不能用。 这又是为什么? 其实在json里,被大括号包起来的整个就是一个对象。所以大括号格式本身就只有一个对象。 而中括号格式里可以放很多个大括号,所以中括号里可以有很多个对象。 而上面这种简化方式,它简化后就变成了一个对象,因为它不能再添加其他的比如color的参数,自然就不能在大括号里放了,只能在中括号放。 (所以这种简化方式不止是删了text,还删除了大括号?) (没错,所以就更不可能在大括号里放了,不然就会变成大括号里再套大括号,格式就不对了) 既然这种简化方式本身并不能添加参数,那么如果要修改颜色该怎么办? 这就要说到对象的类别了。 在json列表里(就是上面说的中括号格式),从左往右数的第一个对象其中的参数会影响其余的所有对象,所以我们通常把第一个对象叫做父对象,而其余的对象叫做子对象。 这个名称取得很符合现实,毕竟现实中也是会基因遗传的嘛。 当然,和现实一样,子对象也可以通过额外添加参数来改变自己,当然父对象遗传下来的参数没有被改变的话仍然是留在那里的。(注意,改变单个子对象的参数并不会改变后面全部子对象的参数看,因为这些子对象都是同级的。如果想改变单个子对象并同时改变后面的子对象,只能把后面的子对象全部变成该子对象的子对象,即孙子对象) 所以你可以通过在父对象就设置好参数,然后在子对象里写简化的文本,比如: [{“text“:““,“color“:“red“},“淦“} 但需要注意的一点是,列表里的每一个对象里都必须要有一个显示内容的元素,比如text或score。当然你也可以将元素留空,这样子就不会出现任何的其他文本了。 (额,这样子直接把第二个对象的内容写在第一个对象里不好吗.......) 对哦,这样子更省事唉。 这些就是json的格式了。 第一百二十二章 json的内容 上 我们都知道在json里面可以使用text来输入文本。 而且我们也知道在基岩版显示文本的地方是可以写目标选择器的。 那么有没有什么办法能不能帮助我们在java版在json使用目标选择器呢? 有! 这就是:selector元素。 selector元素属于内容类别。内容元素能有什么作用?在minecraft的json中,一个json要生效,必须要每个对象都至少有一个内容元素,比如text就是内容元素。 那么selector该怎么用? 很简单,比如: \/tellraw @a {“selector“:“@p“} 这样子写,然后游戏就会根据元素内的内容来转义,分析这个目标选择器,最终得出来这个目标选择器的意思:显示最近的玩家。 好了,然后游戏就要找到距离执行地点最近的玩家,然后就向全服广播: 当然,就算你不填目标选择器也可以,因为游戏仍然把它认为是目标选择器,比如: \/tellraw @a {“selector“:“我靠“} 然后游戏就会寻找名为“我靠”的玩家,但实际上并没有这个玩家。 最后游戏找不到,干脆就不干了,直接给你显示一个空空如也的消息。 但如果真有叫做“我靠”的玩家,那么游戏就会正常显示这个名叫“我靠”的玩家的名字。 对了,还会显示前后缀。 当然,selector还不高级,接下来我们来更高级一些: score(内容类别)——记分板元素 这个score可以显示玩家的指定计分项分数,让你的服务器更加的高级。 score也很简单,其格式大概是这个样子的: {“score“:{“name“:“目标选择器“,“objective“:“计分项名“}} (嘿作者,你不是说大括号里不能套大括号吗?怎么现在就出现了?) (额,凡事都有例外嘛) 我相信各位都看得懂这个格式吧,现在我们举个例子: \/tellraw @a {“score“:{“name“:“@s“,“objective“:“绿宝石“}} 这样子,执行后在场的所有玩家都会知道自己有多少绿宝石了。 然鹅,name不光可以填目标选择器,还可以填*号! 这个*号是什么作用呢? @s类似,也是显示自己的分数,只不过为了准确,还要在显示前面加上“读者”二字。 为何?待会你就明白了。 其实score不光是name和objevctive这两个子元素,还有一个子元素:value。 这个value填不填都没关系,反正填了之后,这个objective就失效了,值就固定显示这个value的值。神奇的是,这个value竟然支持数字(不带引号)和字符串。 至于mojang为什么要添加这个元素,可能是因为方便后期编辑吧。 对了,注意一下,一个对象里只能有一个内容元素,所以你不可能在一个对象里同时写上两个text,不然游戏只会显示其中一个元素。 我们知道,游戏内是可以选择语言的,因为各个地方的语言都是不一样的。minecraft也不例外,里面有很多可选的语言,起码可以满足全球大部分人了。 既然游戏都要这样,那么出名的minecraft服务器也要这样,就算不支持那些奇怪的语言,起码也要支持英文和中文繁体。 那么我们自己开的服务器该怎么翻译? 很简单:使用json里的trante元素就可以了。 trante元素也是属于内容元素,但它和其他元素不一样的是,它并不是完全固定的,而是会根据玩家选择的语言来自动翻译。 看到这你可能会说:minecraft还可以翻译英文中文? 其实并不是这样的,实际上minecraft没有内置的翻译软件,所以trante你只能填翻译标识符。 什么是翻译标识符? 翻译标识符可以指定游戏里的一个特定物品,比如“石头”,它的标识符是: block.minecraft.stone 其中,block是它的类别,minecraft是它的命名空间,stone是它的id。 把它放进trante里: {“trante“:“block.minecraft.stone“} 运行。 唉,输出了一个石头! 这时候把游戏语言换成英文,再运行一次。 唉,输出了一个stone! 你也可以改成其他的语言再尝试一遍,或者是把stone换成其他方块的id也可以,比如红石块(redstone_block) 你也可以尝试把block改成item,然后把id改成一个没有方块状态的物品,比如弓(bow)。 为什么要没有方块状态的物品? 很简单,方块物品id都一样,那就节省节省,只在block里写就行了,item就不用写了。 除了item,你还可以尝试改成其他的东西,比如entity(实体)什么的。 但是如果标识符乱写会怎么样? 这样子游戏就翻译不过来,找不到对应的含义,干脆直接给你输出原文了。 对了,如果你想知道一个游戏中的物品的翻译标识符名,你可以去minecraft wiki该物品的词条中使用“查找”输入“翻译”两字,有大概率会跳出来搜索结果是一行叫做“翻译关键字”,这就是该东西的翻译标识符了。 如果你装了mod,比如工业时代2,你就可以更深入的了解一下这个翻译它到底是怎么翻译的: 1.使用winrar或者其他解压软件打开工业时代2的mod文件。 2.打开assets 这时候你就会发现这里面有两个文件夹:ic2和minecraft 这就是命名空间了,其中ic2就是ic2自个mod的命名空间。 3.打开ic2 这时候你就会发现这里存着这个mod的物品、方块什么的。 其中有一个文件夹它叫ng_ic2,说中国话就是“语言ic2”。 没错,这就是ic2语言翻译存储的地方。 点进去一看,有很多个语言文件。 这时候你就可以上网查一下各个语言的英文缩写,比如英文缩写就是en,中文缩写是zh。 但如果你深入了解过语言的话,你就会知道语言还可以再划分,比如英文由于覆盖范围广,导致出现了加拿大版本、英国原版本、美国版本什么奇奇怪怪的版本,所以这些语言缩写后面还有一个国家或地区的缩写。 其实我们不需要看英文,看中文就行了。 我们发现中午翻译有两个文件: zh zh_tw 很明显那个就是大陆简体,而tw就是台湾繁体,且这缩写还是台湾其字的拼音第一个字符拼出来的。 这里建议大家打开zh的文件,这时候就会出现一大堆的翻译标识符了。 可以发现,这文件的每一行就是一个翻译,格式都是: 标识符=翻译语言 而你可能也同时发现,这标识符竟然其实是没有固定的格式的。 也就是说,就算你再添加一行: nizhenben=我真笨 然后去游戏里面运行一下,那也是丝毫没有问题的。 这就说明什么? 你可以照葫芦画瓢地自己写一个mod,里面全是奇奇怪怪的翻译,然后放到服务器一用,唉,立马就高大上了起来,这下子你的服务器就可以开展跨国业务了! 第一百二十三章 json的内容 下 我们上一章讲到了trante,也就是翻译。我们可以使用游戏里自带的翻译标识符来达成翻译的效果。 我们在第六十章,基岩版的json文本中,讲到了trante,也就是翻译。我们可以使用游戏里自带的语言文件名称来达成翻译的效果。 等等,是不是有什么不对的地方? 这两个竟然作用一模一样!连元素名都长得一模一样!等等,基岩版的trante还有带一个with参数,那么难不成....... 没错!在java版的json的trante,也有一个附加的with参数,作用也和基岩版一样。 唉不对,有一点不一样,就是格式和替换符号不一样。 在java版的json里,with可以识别trante里的%s(下一个参数)和%1$s(第一个参数),其中%1$s中的1可以替换为其他的数字,这个数字代表着显示第几个参数。 而with的格式是这样的: [{“with“:[{原始json文本},对象]}] 等等?这不就是?套娃? 没错,这的确是可以套娃的: [{“with“:[{“with“:[{“with“:[{“with“:[{“with“:[{“with“:[{......}]}]}]}]}]}]}] 而这个with本身的内容是一个列表,按从左到右排列,所以使用%s,第一个%s显示第一个,第二个%s显示第二个,第三个%s显示第三个,以此类推。 那么这个with到底有什么用?对哦,作者在第六十章没讲明白唉。那么这里讲明白吧。 with的作用,就是可以在trante里插入一段固定的文字,不会因为语言的变化而变化。 那么现在来举个例子,比如我们要弄一段文字: <猪>你当我是猪吗? 而其中,“猪”是要翻译的,如果我们只能使用with和trante,就可以这么做: {“trante“:“%s%s%s%s“,“with“:[“<“,{“trante“:“entity.minecraft.pig“},“>“,“你当我是猪吗?“]} 这样子最终得出来的结果是这样的: <猪>你当我是猪吗? 如果调成英文那么是这样的: 你当我是猪吗? 可能有人已经注意到了,作者并没有直接把entity.minecraft.pig放在第一个trante里,而是把它放在了with里。这是为什么? 很简单,放第一个trante游戏就识别不出来了,因为我们还有%s这些干扰项,所以我们只能放出来。 但是如果我的读者里面有外国人,那么这群外国人肯定会表示对这条指令不太满意,因为他们认为说的话里面的“猪”字也可以翻译成英文,那么这该怎么办呢? 很简单,可以修改上面的指令变成:、 {“trante“:“%s%s%s%s%2$s%s“,“with“:[“<“,{“trante“:“entity.minecraft.pig“},“>“,“你当我是“,“吗?“]} 然后把游戏调成英文,再运行一次: 你当我是pig吗? 好了,现在这群外国人都已经表示对这条指令满意了,但是他们对其喜欢的主播造的桥仍然非常不满意,于是作者为了让这群外国人彻底满意,就造出了一个桥,这个桥可以方便河两岸的村民非常“便捷”的来往交易,这群外国人看到我造的桥特别满意,于是每人随手就给了我这本书投了一张推荐票。 好了,这就是trante的全部了,但这不是json内容元素的全部。在json里,还有一个和trante类似的元素,那就是keybind内容元素。 格式和trante差不多,都是要填标识符。而trante是翻译标识符,keybind是按键标识符。 这有什么用?keybind的作用就在于可以非常方便的显示出游戏的按键,把服务器做得高大上起来。特别是使用keybind,还可以制作出一个很简单的新手教程。 而且其显示内容也会随着玩家在设置里更改而更改。 比如: {“keybind“:“key.inventory“}就是显示游戏打开背包的按键,如果玩家没有更改,使用默认设置,那么将会显示e。 是不是很简单?对,但是标识符找起来就难了。 为何?如果你去minecraftwiki找到对应的内容,你会发现其“键位标识符”指向了“控制”词条,而这个词条压根儿就没有键位标识符。 minecraftwiki没有,那么该去哪找呢? 2020年初,minecraftwiki为了方便中国大陆的用户查找资料,分别在bilibili和网易分别设立了镜像,网址分别是: 哔哩哔哩:wiki.biligame.\/mc\/minecraft_wiki 网易:mc.163.\/wikigrab\/ 而哔哩哔哩就是一个真的镜像映射,内容还是minecraft wiki。 而网易就不一样了,还专门重新写了一个界面。但是在其他人看来,网易的这波操作让该minecraftwiki从有用到有个锤子用来了一个一百八十度大反转,其他人宁愿去哔哩哔哩,也不愿去看看网易的镜像站。 那么网易的镜像站就真的没用了吗?还真不一定。 在网易的minecraft wiki首页点击“游戏内容”,往下拉一下,你就会发现了一个新的大陆:原创教程! 实际上这些教程是从minecraft wiki那里搬过来的,但网易把其放在了最醒目的地方,加上界面ui的优化,使我们可以很容易找到这里。 其中,有一篇教程叫做原始json文本,里面详细的说明了原始json文本的各个元素,就在这里,我们就可以找到原版的大部分键位标识符: key.forward——向前移动——w key.left——向左移动——a key.right——向右移动——d key.back——向后移动——s key.sneak——潜行——左shift key.sprint——疾跑——左ctrl key.jump——跳跃——space key.use——使用物品|放置方块——鼠标右键 key.attack——攻击|摧毁——鼠标左键 key.pickitem——选取方块——鼠标中键 key.drop——丢弃所选物品——q key.swaphands——交换副手和主手中的物品——f key.inventory——开启|关闭物品栏——e key.hotbar.[1~9]——快捷栏1到9——1~9 key.savetoolbaractivator——保存物品工具栏——c key.loadtoolbaractivator——加载物品工具栏——x key.chat——打开聊天栏——t key.yerlist——玩家列表——tab key.mand——输入命令——\/ key.fullscreen——全屏显示切换——f11 key.smoothcamera——切换电影视角——无默认按键 key.toggleperspective——切换视角——f5 key.screenshot——截图——f2 key.advancements——进度——l key.spectatoroutlines——高亮旁观者玩家——无默认按键 keybind也完了,那么内容完了没有? 还没完,但也快完了,只剩最后一个:nbt。 nbt也是一个内容元素,使用nbt,可以读取指定实体、方块或命令存储的nbt其中的某个值,并把它显示出来,比如直接显示出一个玩家的经验值,或者是一头阿米驴的血量——哦不!阿米驴被服务器的防刷物品装置清除了!阿——米——驴——! 只不过这个内容,我们就放到接下来讲nbt时再讲吧。 (嘿,作者,json怎么换行啊?) 额,这个...... “\\”这个符号叫做“反斜杠”,和“正斜杠”(\/)是相反的。在计算机语言中,反斜杠通常叫做“转义符号”,而在转义符号后面添加一些数字或字母,是可以有特殊作用的。而json本身作为java的一部分,自然而然也可以使用转义符号。 比如要显示英文的引号,可以在英文的引号前面加上一个\\,让其失去意义,比如: {“text“:“小明说:\\“你好\\““} 这样子,输出的结果是:小明说:“你好“,而两个转义符号是一次性物品,转了“成为没意义的符号就没了。 那么如果想要在文本显示里显示“\\”该怎么办? 很简单,在\\前面再加一个\\让转义符号转前面的转义符号成为没意义的转义符号,这样子就可以显示了,比如: {“text“:“\\\\我去?\\\\“} 这样子得出来的结果是: \\我去?\\ 懂了吧,那么你应该也知道怎么输出: 知道吗,转义符号还可以这么用:{“text“:“\\\\小明:\\“你好\\“\\\\“} 了吧?其实很简单: {“text“:“知道吗,转义符号还可以这么用:{\\“text\\“:\\“\\\\\\\\小明:\\\\\\“你好\\\\\\“\\\\\\\\\\“}“} 那么该怎么换行呢? 可以在转义符号后面添加: \(换行)或\\r(回车)来换行。 为什么有两个呢? 这就要涉及到计算机的操作系统了。 我们知道,目前为止,世界上有四大系统: 苹果系统(mac os、ipai os、iphone os、ios什么奇奇怪怪的苹果旗下系统都统一为苹果) 安卓系统 windows linux 其中,苹果系统采用的是\\r回车符cr代表换行,winodws采用的是\\r和\都用,linux采用的是\换行符lf换行。所以,如果你在linux上使用\且运行正常,那么到了苹果上就可能无法识别只显示一个方框里面显示lf两字。苹果系统换linux也是同理。而\\r也是同理。 所以这就是为什么你在windows上的minecraft使用\\r换行时只会出现一个方框里面有cr两字,这就是因为windows的minecraft可能并不支持\\r,只能使用\,可能换到苹果系统上就没问题了,当然由于minecraftjava是使用java编的,java又是全平台,可能是java并不支持\\r吧,所以虽然可以选择\\r和\,但最好还是选择\来换行。 但是你以为这就完了吗?如果你到百度百科上去搜索“转义字符”,找到转义字符词条,那么你就会发现在计算机语言当中,转义字符的作用不止一点: \\a——响铃(bel) \\b——退格(bs),将当前位置移到前一列 \\f——换页(ff),将当前位置移到下页开头 \——换行(lf),将当前位置移到下一行开头 \\r——回车(cr),将当前位置移到本行开头 \\t——水平制表(ht)(跳到下一个tab位置) \\v——垂直制表(vt) \\\\——代表一个反斜线字符''''\\'' \\''——代表一个单引号(撇号)字符 \\“——代表一个双引号字符 \\?——代表一个问号 \\0——空字符(nul) \\ddd——1到3位八进制数所代表的任意字符 \\xhh——十六进制所代表的任意字符、 而其中,除了\、\\r、\\\\、\\“和\\''(这个也可以用,只不过删了\\也是可以的)上面讲过了或有同类的,剩下的其中\\b、\\f、\\t在minecraft中同样也可以用,只不过和\\r一样,实际上游戏并不能识别它们只不过是json语法对了而已,实践起来只会显示方框里有bs、ff和ht而已。 张三抱着一堆级锋利的剑从刷物品房走了出来,看见王五正在拿着纸和笔专心的做笔记,旁边还放着一台正在工作的电脑。 “奇怪了,王五兄不是最讨厌做笔记了吗,怎么今天像换了个人似的。”张三嘀咕着。 好奇心驱使着张三放下了手中的一堆剑,转而走到正在专心写笔记的王五后面。王五似乎并没有注意到张三来到了他的后面,继续在写东西。 在王五后面的张三定睛一看,发现王五的笔记上面写满了各种密密麻麻的单词、数字,好像是什么计算机语言。“没想到王五竟然会对这种东西产生兴趣。”张三想。 突然间王五伸了一个懒腰,把在后面的张三下了一大跳。王五听见后面有动静,转头一看:“唉,张三兄,你怎么在这里?” 张三平静了一下心情,说:“我这不是刚刚做完事情,出来看到你王五兄你今天竟然在学计算机语言,觉得稀奇嘛所以过来看一下。” 说着张三指了指放在门口的那一堆附了魔的下界合金剑。 王五看到张三这么说,不禁觉得好笑,回答道:“唉张三兄,你还是太高估我了,我那点连初中都没上完的头脑,指望着去学计算机语言?” “嗯?那么你写的是什么东西?”张三听王五这么一说顿时来了兴趣。 “额,这该怎么说呢......哦对了,”说着王五拿起一把下界合金剑,“比如这把剑,它附魔了级的锋利对吧?你想知道为什么这个等级会超过吗?” “额这个问题不是你最先......” “我后来加了几个大佬的qq,和他们仔细研究了好几天,然后我又去某视频平台上看其他大佬制作的教程,还去看了mcbbs的相关文章,同时我还去了minecraftwiki查找了一下文献,最终的结果没有让我失望,我找到了!”王五得意的说。 “原来在minecraft1.13版本mojang把附魔的nbt标签的等级数字类型由short短整型改成了int长整形,自然而然附魔的等级上限就由上升到了!” “你说什么?”张三听得一头雾水,“这和你写的又有什么关系?” “有很大的关系,”王五压低了声音,“你知道腐竹是怎么获得这把剑的吗?” “怎么获得的?快说!” “用了指令!加上nbt!” “?”张三头上的雾水更多了,“那然后呢?” “我在网上找到了一位大佬,他给出了如下指令。”说着王五打开了他的笔记本,并翻到了第一页指了其中一行,“呐,就是这个。” 张三拍散了头上的雾水,然后把目光转向了王五指着的那一行,只见上面写着: \/give @sherite_sword{“enchantments“:[{“lvl“:,“id“:“sharpness“}]} ? 张三头上冒出了个大大的问号:“就是这么简单?” 王五笑着说:“没错,而且这可以直接在聊天栏输入并运行。” 张三虽然不知道为什么王五会笑,但他听王五这么一说,赶紧打开了聊天栏,输入了王五刚刚提供的那个指令,并回车: [未知的命令 \/give @sherite_sword{“enchantments“:[{“lvl“:,“id“:“sharpness“}]}<——此处] 张三:? 王五看张三一脸疑惑的样子,笑得更加的猖狂了:“哦对了哈,张三兄。” 张三以为王五又有什么重要的事情来讲,打起了10倍的精神准备迎接接下来的内容,以免又是一头雾水。 “哪会那么简单啊哈,你只是完成了第一步而已!接下来,你需要找到末地传送门,注意是没激活的!激活的就弄不了了!”王五强忍着笑意装正经说,“然后你需要将一把满耐久的没有附魔的下界合金剑丢进下面的岩浆,静静等待5分钟,这5分钟千万不要动!到点了后你就需要激活传送门,然后跳进去,你就会被传送到一个神秘的房间,这个房间里面放满了神器!我们在管理员手中买到的只不过是最初级的而已,里面还有更加牛批的!” “真的?”张三现在恨不得立马传送到末地传送门旁边。 “千真万确,我们可是好哥们我咋会骗你呢?不信你可以现在就启程。” 张三听王五这么一说,更加确认了王五说的是真的,毕竟是好哥们嘛。于是他操起一把下界合金剑,就进入了地狱门....... “哈哈哈哈哈哈哈哈哈哈哈哈哈哈,哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈,哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈咳~。” 第一百二十四章 json的格式元素 我们在第十七章时讲到了json里可以使用color(颜色)以及bold(粗体)、 italic(斜体)、 underlined(下划线)、 strikethrough(删除线)、obfuscated(乱码)元素来对文本进行修饰。而这些,都叫做“格式”元素,因为通过它们可以修饰或更改文本的格式。 比如: {“text“:“作者被作者击败了“,“color“:“red“} 在游戏里运行就会输出红色的“作者被作者击败了”。 而{“text“:“额“,“italic“:“true“,“color“:“yellow“}则会输出斜体黄色字:额。 这些我们在那一章都讲过了,这里就不再叙述了。 那么json的格式元素只有这些吗?肯定不止。 只不过再讲之前,作者还要补充两点: 上面的bold、italic、underlined、striketrough、obfuscated都是布尔值,你可以加上引号,但其实不加引号也是可以的,比如上面的{“text“:“额“,“italic“:“true“,“color“:“yellow“}就可以写成{“text“:“额“,“italic“:true,“color“:“yellow“},在命令方块里运行还是一样的。当然作者推荐布尔值还是不要加上引号,虽然现在json的格式并没有那么严,可能以后就严起来了。 而且,你知道吗,在1.16版本,color已经不止17种颜色了。 为什么?因为在1.16版本,你已经可以这样子了: {“text“:“看这个颜色“,“color“:“#1f2712“} 这是什么?这是16进制颜色代码,是rgb颜色化成16进制的样子,常用于网页中。 具体的话你可以去百度百科上看看。 好的,接下来我们来看一下剩下的这些格式元素吧,其实这里不应该用“这些”的。‘ 为什么?因为只剩下了一个,这个是java1.16新添加的: font 这是什么作用呢? font的作用就是可以更改字体! 比如我们的minecraft默认字体就是:minecraft:default,其中minecraft为命名空间。填入font: {“text“:“字体“,“font“:“minecraft:default“} 然后运行: 字体 嗯,很普通是不是?因为我们选择的是minecraft的默认字体。 那么font除了选择自家的字体,还可以选择其他的字体吗? 可以!你只需要找到一个带有其他字体的1.16材质包,准确来说是1.16资源包,然后装上。你可以打开这个资源包看一下它的命名空间,顺便看一下它的字体文件名,assets文件里面的第一层那些文件夹名就是命名空间,和mod文件是一样的。字体文件存储在命名空间下面的font文件夹里面,如果材质包有自带字体的话就有font文件夹,否则没有的话你就只能再去找一个。 或者是右转去问问百度贴吧的吧友,然后水贴两小时,最后啥也没获得。 哦对了,还是有获得的: 经验+3,岂不美哉?——[三国]王司徒 (呃,只写了700多,不行啊,那么再加一点料吧) 我们知道,在基岩版,你是可以使用§来更改文本的颜色和格式的,那么在java版行不行呢? 当然行。 但是你无法在聊天来输入§,这是为什么?因为§在java版是属于非法字符的。如果你在服务器的聊天框输入,你甚至还有可能因为非法输入而被踢出服务器,当然大多数情况下聊天栏并不会显示任何东西,因为游戏识别不出来。 而你却可以在java版的书与笔中输入,只不过并不会显示,但是当你再输入一个数字或字母时,只要符合§的格式,就可以成功被游戏识别出来,你的文字颜色也会同时被改变。 而在游戏外,用的地方就很多了。你就可以在资源包、存档、mod名等地方使用§了,比如你可以修改资源包的名称,在其最开始的地方添加一个“§e”,这样子当你再次打开游戏,资源包的名称就全变成黄色的了。 而存档名就比较麻烦,你需要一个nbt修改器,如nbtexplorer,然后打开要修改的存档文件夹里的level.dat文件,找到levelname(世界名称)标签,你就可以自由的修改存档名以及样式了。 同样的逻辑也可以用于服务器,比如服务器的简介以及世界名。只不过简介的话虽然可以直接在server.properties里修改motd属性,比如: motd =§e look!this a minecraft sever! 但是当你打开minecraft,想要查看成果时,你就会发现服务器的简介变成了: ? look!this a minecraft sever! 虽然成功变成了黄色,但是前面竟然多了一个灰色的“?”! 这是为什么?因为服务器在读取配置文件时,不知道你写的这个§到底是什么鬼东西,于是只好将其先转化成:\\u00c2\\u00a7,即?§,简介就变成了: \\u00c2\\u00a7e look!this a minecraft sever! 然后到了客户端时,客户端读取时发现“唉,这里竟然有一个§e”,于是就自动转化后面的字符为黄色,这就变成了你看见的: ? look!this a minecraft sever! 如果你此时再次打开配置文件,你就会发现服务器自动转化简介成了: \\u00c2\\u00a7e look\\!this a minecraft sever\\! 其中两个在感叹号前面的\\还好理解,这就是我们上一章说过的转义符号。而我们的: §e 就被转换成了: \\u00c2\\u00a7e 其中,这种\\u00a7代码叫做unicode,即“统一码”,从其开头的\\u就可以看出来。后面的00a7则是§的统一码编号。而客户端读取的时候就会自动转换统一码。 所以,我们可以再输入的时候直接输入§的统一码,即:\\u00a7,然后在后面加上其他的数字或字母,这样子就不会出现多余的?了: motd =\\u00a7e look\\!this a minecraft sever\\! 然后客户端就显示正常了: look!this a minecraft sever! 王五正在电脑上的qq和他最近认识的大佬聊天。 17:25 王五:大佬,额这个分节符该怎么输入啊? 刘一(王五认识的大佬):在windows,可以按alt+numpad0+numpad1+numpad6+numpad7;在macos,按下option+6;在linux,按下pose+s+o 刘一:就可以了。 王五:这个numpad2这些是什么键? 刘一:哦,这个就是你键盘右边的那个小键盘,后面的数字对应着小键盘上相应的键,比如numpad0就是按住小键盘上的0。 王五:也就是说我打出分节符只需要按住 王五:alt+0167就可以喽 刘一:没错,就是这样的,只不过数字是按顺序按,并不需要按住数字,alt才需要按住。 王五:哦,那我试试。 王五:§,我的天! 刘一:怎么样? 王五:ohhhhhhhhhhh! [叭] 王五兴奋地合上了电脑,然后拿出了书与笔,嘴里念着: “alt加0167,然后1,接着输入蓝色,嗯,完美。” 然后他带着这本书走出了基地。 [过了一会儿] “我的天终于回来了,天杀的,那王五竟然坑我!”张三突然出现在床旁边,“妈的,要是劳资没点水平,那就差点在末地丧命了!” 张三环顾了一下他的小房间,这时他觉得这个橡木木板做成的小房子是如此的温馨,那摆在窗台的花盆是如此的美丽,那停止运作的刷物机是如此的....... 然后他看向了手中那整个服务器唯一的龙蛋,以及他从生死的悬崖旁边获得的龙头和鞘翅,忽然间就笑了:“原来这才是王五的真正意思啊。” “我们马上就要成为全服最牛逼的一群玩家了!ohhhhhhhhhhhh!” 第一百二十五章 玩家与json的交互事件 上 看,这是一段json文本输出的文字。 只不过这段文字就是一段文字,你无法操控它,或者是它操控你(???)。 如果你真的可以点击这段文字并产生一些作用,比如打开了一个新的网站,你点击文字的做法,就叫做你与文本的“交互事件”。 在json文本中,专门管理玩家与json文本的交互事件元素统称为“交互事件”。 下面,我们就来研究研究,这些交互事件元素,到底该怎么用。 第一个:insertion。 第一个也就是最简单的一个。insertion的作用就是当玩家按住shift并点击insertion所在对象显示的文字时,游戏就会自动将insertion的值填入聊天框中,且并不会覆盖已在聊天框输入的文字,比如: {“text“:“按住shift点击有惊喜“,“insertion“:“惊喜!“} 运行之后你就会发现输出了: 按住shift点击有惊喜 这样一段普普通通的消息。但如果你点击t键打开消息界面,并按住shift点击文字,你就会发现聊天栏自动输入了:“惊喜!”二字。 这就是insertion的用法,是不是特别简单? 只不过该元素只有出现在聊天栏时,比如使用tellraw执行才有意义,你直接写在告示牌或者是书里是没有任何用处的。 然后第二个:clickevent clickevent元素的作用就是当玩家点击文字(注意没有按shift,是直接点击的那种)所产生的事情。所以clickevent从该层面上来讲就和超链接很类似了(自信点,把“类似”去掉)。 既然是超链接,这让你想到了什么? 首当其冲的肯定就是打开网址,没错,clickevent确实可以实现。 然后呢?然后我们就不要再联想了,直接看看clickevent到底该怎么用吧。 clickevent元素的值是一个对象,即: {“clickevent“:{}} 在clickevent值里面有两个参数: action和value。 这两个参数都是必须填的,其中action为设置点击后会产生什么样的事情,value就是点击产生的事情所需要的值。 action有六种事件: open_url——使用系统默认浏览器打开value的网址 open_file——打开位于value路径的文件 run_mand——运行value中的指令 suggest_mand——打开聊天栏并输入value里的值,会覆盖原本输入的消息 change_page——翻页到value页 copy_to_clipboard——将value里的值复制到粘贴板 open_url是最常用的事件,当玩家点击的时候游戏会跳出一个界面: 你确定你要打开以下网页? 然后下面还有一行粉红色的字: 永远不要打开从你不信任的人得到的链接! 接着就是三个选项:是、复制到剪贴板、否 如果选是,那么游戏将会使用默认浏览器打开;如果选复制到剪贴板,将会真的复制到你的剪贴板,只不过网页需要你自己打开浏览器复制进去;如果选否,那么恭喜你,啥也不会发生,只不过界面被关掉了而已。 那么如果我们要点击的时候打开百度搜索首页该怎么办? 很简单: {“text“:“百度搜索“,“clickevent“:{“action“:“open_url“,“value“:“ 运行,点击一下“百度搜索”再点击“是”你就发现你打开了百度。 等等,这样子做的话,那么我们是不是可以在服务器里做出一个网址大全? 嗯,一个很不错的想法,可惜你的想法早在1999年就被李兴平想到了,只不过鉴于你是在服务器里做的网址大全.......或许会因为其特殊性吸引更多的用户? 然后是第二个:open_file open_file和open_url类似,只不过open_url是打开网上的网址,而open_file是打开本地的文件,比如: {“text“:“你猜猜这有什么用“,“clickevent“:{“action“:“open_file“,“value“:“c:\\\\“}} 点击就可以打开c盘.......?为什么不能打开? 为什么呢? 我们找到minecraft wiki,会发现上面说了一句话:“ 且出于安全原因禁止玩家使用。” 原来如此!mojang竟然考虑得如此周到!不愧是mojang! 所以open_file无法在游戏里运行,但是在游戏外,比如你开发的mod,就可以运行。 open_file在minecraft的作用就是用于游戏自动产生的消息中,比如你按了f2截图,你就会发现你可以点击消息中的带有下划线文字部分来打开你的截图照片。 (等等,那么用在mc函数中可以运行吗?) 第三个:run_mand run_mand就比较直白了:运行指令。比如: {“text“:“你猜猜这有什么用“,“clickevent“:{“action“:“run_mand“,“value“:“\/give @p diamond“}} 运行,并点击一下文字,你会发现你获得了一颗钻石! 但如果你忘记在value的开头打上\/,那么你就会发现你发送了一条消息:give @p diamond 这是怎么回事? 这就要联系到run_mand的运作方式了。 在聊天消息以及书里,当一位玩家点击了带有run_mand属性的clickevent那段文字,游戏就会默认该玩家为指令执行者,并自动在该玩家的聊天栏输入value里的指令并发送。 所以说,run_mand就只是点击发送消息咯? 没错就是这样的,具体能不能执行只能看该玩家的权限等级了。 那么该怎么样让不够等级的玩家也能使用run_mand运行指令呢? 用告示牌就行了。 但是在告示牌上面怎么写json啊? 很简单,用指令放置一个带有json的告示牌就行了,比如上面这条指令就可以: \/setblock ~~~ minecraft:sign{text1:“{\\“text\\“:\\“你猜猜这有什么用\\“,\\“clickevent\\“:{\\“action\\“:\\“run_mand\\“,\\“value\\“:\\“give @p diamond\\“}}“} (注:此为1.13版本指令,低于该版本或高于该版本均无法使用,其他版本: 低于1.13——\/setblock ~~~ minecraft:standing_sign 0 rece {text1:“{\\“text\\“:\\“你猜猜这有什么用\\“,\\“clickevent\\“:{\\“action\\“:\\“run_mand\\“,\\“value\\“:\\“give @p diamond\\“}}“} 高于1.13——\/setblock ~~~ minecraft:oak_sign{text1:“{\\“text\\“:\\“你猜猜这有什么用\\“,\\“clickevent\\“:{\\“action\\“:\\“run_mand\\“,\\“value\\“:\\“give @p diamond\\“}}“}) 运行一下,你就会发现出现了一个告示牌,如果你一直点这个告示牌,那么你就一直会获得钻石。(注意不是左键啊,是右键) 而且,就算你撤了你的op,你还是可以获得钻石。 并且!在告示牌上,你是不需要在value的开头加上\\的。 为什么? 因为在告示牌上,你点击了告示牌,游戏会检查告示牌的json,发现了clickevent,游戏就会发现这个json不简单,于是检查了一下clickevent,发现了run_mand。 此时游戏恍然大悟,然后游戏就把value交给了服务器处理。服务器会把这条value按照命令方块处理指令的方式来处理,这个时候指令执行地点就是告示牌,指令执行者就是命令方块。 而命令方块处理指令本身也就不需要加上\/,自然告示牌上的json运行指令也就不需要加上\/了。 第四个:suggest_mand suggest_mand很简单,就是玩家点击时将value的值覆盖(注意这个词)到玩家的聊天栏输入框,玩家可以自由选择要回车,还是删掉。这很简单就不再多说了。 第五个:change_page change_page这个是专门给书用的,就是在书里点击文字就可以自动跳转到value值的页面,比如: \/give @a written_book{author:“你好mc“,title:“《minecraft指令手册》第一卷“,pages:[“{\\“text\\“:\\“第五章:坐标\\“,\\“clickevent\\“:{\\“action\\“:\\“change_page\\“,\\“value\\“:4}}“,““,““,““]} (此为1.13版本指令) 获得一本由你好mc写的“《minecraft指令手册》第一卷”,然后在第一页里显示着: 第五章:坐标 点击这串文字,就会自动跳转到3-4页。 如果你细心观察上面的指令,你就会发现这里的value不是字符串,而是数字。 没错,change_page属性的value只能是数字值,不能选择字符串或者是布尔值。 这就是change_page的用法。 第六个:copy_to_clipboard 这是在1.15版本才加入的新功能,作用就是玩家点击时可以自动将value值复制到玩家的剪贴板,通过这个功能或许可以方便我们让服务器更加的智能化。 由于篇幅有限,剩下的内容我们下章再讲。 —————————————— clickevent各事件可用性: open_url——聊天界面、书 open_file——无法在游戏里使用 run_mand——聊天界面、书、告示牌 suggest_mand——聊天界面 change_page——书 copy_to_clipboard——聊天界面、书 第一百二十六章 玩家与json的交互事件 下 现在,我们知道玩家和json文本的交互方式有按住某个键并点击,或者是直接点击文本。 只不过从广义上来讲,这都是要点击文本。那么有没有什么不用点击文本就可以与文本产生交互事件的元素呢? 有!这就是:hoverevent hoverevent的作用是当玩家把鼠标指针移到文字上面时产生的事情,而不是点击。 hoverevent和上一章讲的clickevent比较类似,值都是一个对象,由action和value组成。 有了上一章的经验,这两个的作用也就不需要再讲了吧? action有三种事件: show_text——显示条平平无奇的json文本 show_item——显示一个物品的悬浮介绍文字 show_entity——显示一个实体 show_text无疑是最简单的,你可以这样: {“text“:“快摸我!“,“hoverevent“:{“action“:“show_text“,“value“:“太棒了!感觉怎么样?“}} 这样子就会输出一串文字:快摸我! 如果你把鼠标放在了上面,你就会发现上面出现了一串文字:太棒了!感觉怎么样? 你也可以这样: {“text“:“快摸我!“,“hoverevent“:{“action“:“show_text“,“value“:{“text“:“太棒了!感觉怎么样?“}}} 或是这样: {“text“:“快摸我!“,“hoverevent“:{“action“:“show_text“,“value“:[{“text“:“太棒了!感觉怎么样?“}]}} 甚至是这样: {“text“:“快摸我!“,“hoverevent“:{“action“:“show_text“,“value“:[{“trante“:“%s“,“with“:[{“trante“:“%s“,“with“:[{“trante“:“%s“,“with“:[{“trante“:“%s“,“with“:[{“text“:“太棒了!感觉怎么样?“}]}]}]}]}]}} 都是可以达到一样的效果的,你也可以添加一些别的元素,比如改变文字颜色什么的。 然后是show_item,这个的作用详细一点说,就是放在文字上面可以显示一个物品的详细信息,就像是你在背包里把光标移到物品上面一样。 show_item的value也是字符串,但是里面还要写一个对象,所以里面的引号前面都要加上转义符号,不理解的可以去上一章看看作者是怎么用指令放置一个带json的告示牌的,那条指令里面的json文本就跟这里的value是差不多的。 ok,那么具体要怎么做呢? 在第一百零八章,我们讲到了物品的通用标签: “count——物品堆叠的数量 slot——物品所在的栏位(为掉落物时没有这个值) id——物品id,神奇的是如果你不填,那么生成出来的掉落物就是一块石头 tag——这个接下来就是物品的非必填标签了,比如ench等都在里面。” 在这里,我们也需要用到物品的通用标签,这里我们拿悬浮显示一个“苹果”的悬浮文字举例。 我们需要先把value外边的json先给理清楚: {“text“:“快摸我!“,“hoverevent“:{“action“:“show_item“,“value“:““}} 然后我们就可以研究研究value该怎么写了,首先肯定要加上id,这是必须的: “value“:“{id:\\“minecraft:apple\\“}“ 然后你可以试着先执行一下: {“text“:“快摸我!“,“hoverevent“:{“action“:“show_item“,“value“:“{id:\\“minecraft:apple\\“}“}} 只不过光标一放上去,就显示了一条红色的文本: invalid item 这句话的意思是:无效的物品 既然无效,那么肯定就是我们有必填项没填,可以试着加一下count参数: “value“:“{id:\\“minecraft:apple\\“,count:1}“ 然后再试一下: {“text“:“快摸我!“,“hoverevent“:{“action“:“show_item“,“value“:“{id:\\“minecraft:apple\\“,count:1}“}} 你就会发现,你成功显示了一个苹果! 只不过显示苹果并没有什么奇特的,因为看起来这就跟普通的显示文本差不多啊? 其实并不一样,因为这个苹果文本和我们之前说过的trante显示出来的翻译文本差不多,你只要改变一下语言,再把光标一放,唉,立马就不一样了!而且还是实时更新,不需要更改语言后再执行一次。 只不过这还不是最特别的,你还可以尝试一下把苹果(apple)改成钻石剑: {“text“:“快摸我!“,“hoverevent“:{“action“:“show_item“,“value“:“{id:\\“minecraft:diamond_sword\\“,count:1}“}} 然后光标再一放: 钻石剑 在主手时: 1.6攻击速度 7攻击伤害 是不是一模一样? 那么这有什么用处呢? 如果你平常仔细观察,你就会发现如果我们使用\/give指令: \/give @s diamond_sword 这样子获得一个钻石剑,把光标放在提示消息上,也会出现一样的效果。 最后一个:show_entity show_entity这个和show_item差不多,value值也是字符串,仍然需要转义,只不过从物品变成了实体而已: {“text“:“快摸我!“,“hoverevent“:{“action“:“show_entity“,“value“:“{}“}} 那么对象里面该填啥呢?可以填实体的name(名字)、type(种类)、tag(nbt标签)和id(uuid)。 这三个属性可以方便我们“伪造”出一个虚拟的实体,比如我们最基础的可以伪造一名叫做“人”的玩家: {“text“:“快摸我!“,“hoverevent“:{“action“:“show_entity“,.“value“:“{name:\\“人\\“,type:\\“minecraft:yer\\“}“}} 但是当你把光标放在上面之后,你就会发现:“唉,咋啥都没有呢?” 别慌,我们可以再填一个id: {“text“:“快摸我!“,“hoverevent“:{“action“:“show_entity“,“value“:“{name:\\“人\\“,type:\\“minecraft:yer\\“,id:\\“b5bef018-4307-48c8-894c-391f7bc3d8db\\“}“}} 运行之后,唉还是没有出现。 这到底是怎么回事? 额,这个作者也不知道,但估计是版本的问题,于是作者换了一个版本(1.13.2到1.12.2): \/tellraw @a {“text“:“快摸我!“,“hoverevent“:{“action“:“show_entity“,“value“:“{name:\\“人\\“,type:\\“minecraft:yer\\“,id:\\“b5bef018-4307-48c8-894c-391f7bc3d8db\\“}“}} 结果还是不行。 那么或许我们可以换一种思路——使用真实存在的玩家行不行? 为此作者又测试了一下,还是不行。 那就算了吧,可能是特性,毕竟如果错了,起码应该还有一个invalid entity的提示信息,啥也不显示估计是真的游戏bug了。 那么这就代表着本章结束了吗? 不,还没有! minecraft 1.16更新,mojang不用了value(我们还可以用,是支持的),转而使用了contents参数。contents参数和value类似,但有些地方有稍稍改进,比如show_item和show_entity就再也不是字符串了,所以我们的显示钻石剑就要被迫改成: {“text“:“快摸我!“,“hoverevent“:{“action“:“show_item“,“contents“:{“id“:“minecraft:diamond_sword“,“count“:1}}} 可以发现,1.16的nbt更加json了,参数都要加上引号了。 那么我们的show_entity能用了吗?可以测试一下: \/tellraw @a {“text“:“快摸我!“,“hoverevent“:{“action“:“show_entity“,“contents“:{“name“:“人“,“type“:“minecraft:yer“,“id“:“b5bef018-4307-48c8-894c-391f7bc3d8db“}}} 结果还是不行,但既然到了最新版本还不行,这是否代表着我们是填对的,只不过....... 没有可以显示的东西? (注:1.16版本,实体的name标签已经支持了json文本。) 第一百二十七章 json剩下の一些东西 我们知道,在json里,对象有分为父对象和子对象,第一个对象肯定是接下来的对象的父对象。 只不过这种父对象子对象一般只会在[]这种json列表里才会遇到,{}里一般用不到。 如果{}里也要分父对象和子对象呢?那就要使用“extra”元素了,这位元兄已经在之前出过很多次场了。 extra是这么用的: {“内容元素“:“一些内容“,“extra“:[{},{}......]} 没错,使用extra,就可以在一个对象里再放入许许多多的对象。只不过这时候你可能会问:唉那extra里面的这些对象的父对象到底是哪个对象呢? 很简单,我们可以拿json的列表说话: [““,{“内容元素“:“一些内容“,“extra“:[{},{}......]}] 在这里,最外层的列表的父对象是第一个,第二个带extra的是子对象。 子对象的孩子,也就是extra,都是子对象的子对象,也就是孙子对象。 所以extra里面的对象全部都是孙子对象,而它们的父对象,就是extra本身元素所待的对象。 懂了吧?所以一个对象里的extra里的所有对象,其格式会照搬extra本身所在的对象。 只不过请注意一点:在你打指令之前,请你先注意一下extra本身所在的对象有没有内容元素,extra本身并不是内容元素! 这就是extra的用法。 但这并不代表本章结束了,你还记得第一百一十九章的这串指令吗: \/team modify 称号生存带师 prefix [{“text“:“[lv.“,“color“:“red“},{“score“:{“name“:“*“,“objective“:“等级“}},{“text“:“]“,“color“:“red“},{“text“:“[生存带师]“,“color“:“red“}] 如果你真的去试了,你就会发现,实际上是这样的: <[lv.][生存带师]lbwnb>谁有铁啊!!!我真的很缺铁哎!!!> 这是怎么回事呢? 因为score出错了。 score显示的分数只能是一个玩家的,所以score的name目标选择器不可以选中多个目标,或者是指定名称。 但是我们上面使用了*,这到底是干啥的呢? 你如果没跳过第一百二十二章的话,你就应该知道,*号的作用当时作者描述的是:显示自己的分数。 如果你语文比较好,注意力和观察力都是中偏高的,你就会发现上面这段描述有些问题: 显示谁自己的分数? 肯定是显示读者自己的分数。所以,*号并不能拥有多个读者,这样子它才不会逻辑混乱最后劳资不干了。 这时候问题就来了:怎样确定一个文本有没有多个读者呢? 我们常用的tellraw,格式相信你也知道,是这样的: \/tellraw <目标选择器> 在执行指令的时候,我们的游戏会先执行目标选择器,寻找符合的目标。 然后游戏会将json文本作为聊天消息分发给这些目标,然后再解析。这样子每个目标读到的json文本实际上都是独立的,自然就不会出现“一串文本有多个读者”的情况。 但如果是我们的队伍前后缀呢?可以发现设置的时候是没有目标选择器的,所以游戏并不会分发,而是直接公示,结果这就导致一串json文本会有很多读者,自然而然score就发挥不了作用了。 嗯,json的内容基本上就到这了,json的nbt我们放到下一卷讲nbt时再来讲。 第一百二十八章 营销号写指令教程 在继续讲nbt之前,我们可以先休息一下,来研究研究点其他的: 营销号写的指令教程 相信在座的各位应该都知道营销号是怎样写出一篇文章的吧?方法有三个: 1.mand+c然后mand+v 2.找外网的一些视频,然后套外国小哥的模板,最后发布 3.xxxxxx是怎么回事呢?xxx相信大家都很熟悉,但是xxxxxx是怎么回事呢,下面就让小编带大家一起了解吧。xxxxxx,其实就是xxx,大家可能会很惊讶xxx怎么会xxx呢?但事实就是这样,小编也感到非常惊讶。这就是关于xxxxxx的事情了,大家有什么想法呢,欢迎在评论区告诉小编一起讨论哦! 但如果营销号要写指令教程,2和3肯定是不行的,所以只能选择:mand+c然后mand+v来盗用别人写的文章。 比如这篇在2018年08月17发布于 (以下内容为摘取片段) 2.查找物品。如果你想要查找某个物品具体在什么位置,那么你可以使用命令\/neveg find ,这个指令可以查找在线玩家的背包。可以查找的选项有disy(根据自定义名称)和lore(根据lore、属性)。例如如果你使用了\/neveg find disy 幽灵这个指令,则会返回到背包有包含幽灵的玩家名单。 3.\/testfor,这个指令简单地来说就是隐藏红石信号,如果玩地图的时候你没有踩到任何拌 线钩或压力板,可是却会有红石信号输出,这个就是\/testfor的奇妙之处,假如你想让一个地方有隐藏红石,指令就像这样\/testfor 。 (以上内容为摘取片段) 先不说说这篇文章有没有抄袭,我们看看这个片段讲到了\/neveg和\/testfor这两个指令。\/neveg这条指令原版是没有的,但这篇文章并没有标注这是哪个mod的指令,也没有说这是一条mod指令。作者查了一下,这条指令是一个叫做“neveg”的防熊插件的指令,作用是查找在线玩家的背包,方便腐竹检查违禁品,这里说的还算是正确。 但下面这个\/testfor就很奇怪了,作者在本书的第三十六章,明确的讲到了testfor是用于探测实体的,而这里明确的写到:“......这个指令简单地来说就是隐藏红石信号,.......” 隐藏红石信号?兄弟啊,有没有抄袭就先不追究,关键是您这是在误导新手还是在讲笑话啊?如果是误导新手的话,我记得mc玩家都挺不喜欢老玩家去坑新手吧? 好了,那么接下来就是重头戏:这篇文章到底有没有抄袭。 答案是肯定的:有! 验证过程很简单,把上面这一段复制到百度搜索框里,按下回车。 最后结果挺不让人意外的,app.myzaker.(zaker)、 这些营销号写的教程都是复制粘贴过来的,它们虽号然在某种意义上推广了文章,但却并没有让写这篇文章的人获得什么,真正获益的只是那些营销。 真的吗?其实营销号还更加猖狂。 2019年8月25日,我的世界百家号官方发布了一篇名为:“《我的世界》新版本的指令变化,老mc:终于实现傻瓜式操作了!”的文章。 现在我们可以复制一下这文章的内容,搜索一下,你就会发现这些营销号竟然连官方的都盗!更神奇的是作者找到看点快报上相同的文章,这篇文章肯定是盗我的世界官方的那个,只不过如果你去看这篇文章的发布时间:1970-01-01 08:00 1970年?难不成这篇文章是在unix系统上写的? 综合各种营销号的指令教程来看,我们不难发现营销号的指令教程通常有以下几个特点: 1.几乎都是抄的 2.不分原版指令和mod指令 3.大部分集中在游侠网、游民星空等这类中小型网站,也有些发布于百家号、哔哩哔哩这些大平台,只不过较少。 4.不分mc版本 所以,以后想去找指令教程,最好去百度贴吧、minecraftwiki、mcbbs、mc百科、我的世界网易官网这些较官方或论坛网站,游侠网这类网站的指令教程固然可以研究,但还是要少看,因为作者刚入mc的时候就被坑过。 如果你也被营销号写的教程给坑过,那么留个言吱一声,我们下章就要开始继续讲nbt了。 第一百二十九章 深入地了解一下实体 我们知道,在minecraft,方块、实体、粒子是三种常见的东西。 其中,方块还可以按照性质细分为: ——流体(水、岩浆...) ——气体(空气、洞穴空气...) ——固体(石头、木板...) 而固体又可以按照重力分为: ——可下落方块(沙子、混凝土粉末....) ——可浮空方块(圆石、灵魂沙...) 既然方块都能分出这么多类别,那么实体呢? 也可以分,虽然我们在三十一章时就分过了,但这次我们是要正经的分的。 实体可以按照性质分为: ——玩家[yers](minecraft中可被控制的角色) ——生物[mobs](除玩家外拥有生命值、碰撞箱,拥有ai,可自主移动的实体。比如:僵尸、羊) ——交通工具(可被玩家乘坐并控制的实体。比如:马[这也是生物]、船) ——矿车[minecart](可在铁路上行驶的实体。比如:运输矿车、命令方块矿车) ——物品[item](处于实体状态的物品。比如:掉落物) ——经验值[experience](处于实体状态的经验值,可被玩家吸收。比如:经验球) ——弹射物[projectile](拥有重力,撞击后会碎裂或停止,大部分会对非弹射物实体造成击退甚至伤害。比如:鸡蛋、末影珍珠) ——tnt[tnt](tnt的实体形式,会爆炸。比如:激活的tnt、核弹[ic2]) ——下落的方块(产生于可下落方块下落时,当遇到地面会转化成方块,又叫实体方块。比如:下落的方块) ——盔甲架[armor stand](不会自主移动,可被推动,可装备,有生命值) ——其他(剩下的一些零碎的实体类别:末影之眼、烟花火箭、浮漂、闪电、栓绳的结、画、java版的物品展示框、潜影贝导弹、末影水晶、尖牙) 其中,生物按习性可以分为: ——敌对生物[monster](会主动攻击玩家。例如:僵尸、小白) ——中立生物(在被激怒后才会攻击。例如:末影人、羊驼) ——被动生物(玩家攻击后也不会反击。例如:羊、村民) ——boss生物(血条厚,耐打,玩家靠近会显示boss血条) 而被动生物还可以分为: ——和平型被动生物(不会直接对其他生物造成伤害,比如:羊、鸡) ——防御型生物(会对其他生物造成伤害,但并不会主动攻击。比如:河豚) 玩家也可以分,具体分为: ——steve(模型是steve的玩家) ——alex(模型是alex的玩家) 是不是没想到啊?这里科普一下,玩家的皮肤不管怎么换,模型都只有两种:steve和alex,明显区别就在于手臂的粗度,steve比较粗,alex比较细(这大概就是一个男一个女的区别吧)。 现在你已经知道了实体有很多类别,但其实你也并不需要全记下来,因为常用的也就那么几种:玩家[yer]、生物[mobs]、弹射物以及盔甲架。掉落物和下落的方块在一些时候也比较常用,比如制作地图或者是拍个《用晃晕你的方式打开mc》。 既然实体有这么多的类别,那么我们是否可以根据它们的性质进行个归类呢? 可以! 比如我们可以按照“自然消失”来归类: 会自然消失——生物、掉落物(5min)、经验值(5min)、部分弹射物(箭、三叉戟:1min)、末影之眼(≈10sec)、烟花火箭(爆炸)、tnt(爆炸)、闪电(1~3tick)、浮漂(1min)、尖牙(1~2sec)、下落的方块 不会自然消失——玩家、非生物交通工具、矿车、部分弹射物(雪球、末影珍珠等)、拴绳的结、画、物品展示框、盔甲架、潜影贝导弹、末影水晶 也可以按照其他的比如生命值、固体性质什么的来归类,具体作者我就不再列举了。 分类完了,我们该干些什么呢? 研究研究实体的运动?当然可以。 我们知道实体是会受到重力影响的,而我相信你的小学老师曾教过你一篇课文:《两个铁球同时着地》。简单概括这篇课文呢就是伽利略证明了物体的下落速度跟物体本身的质量一毛钱关系都没有,同时赞扬了伽利略不迷信权威的独......唉总之呢,伽利略的这个实验纠正了“自由落体定律”中的错误。 那么问题来了,如果我们学着伽利略做这个实验该怎么做?肯定不能在现实世界做,万一被人发现我们在高空抛物就完蛋了。所以我们可以在mc中做这个实验。 我们在mc中的天上同时丢下铁锭和铁块,可以发现他们的速度都是差不多的,这说明mc的重力也是比较科学的。 真的是这样吗? 现在我们把铁锭换成羽毛,然后又在天上同时丢下,现在你可以猜一下最终情况是怎么样的: a.铁块先落地 b.羽毛先落地 c.同时落地 d.无法确定 按自由落体定律,mc主世界并不是真空,而是有空气的,所以轻的羽毛必然会被空气阻力拖住而缓缓下落,重的铁块空气阻力几乎拖不住,必然会比羽毛提前到达地面。 但实际上并不是如此,是两个东西同时到达地面。 这说明了什么?如果还要继续以自由落体定律解释的话,那就是我们的mc的大气非常稀薄,稀薄到几乎没有,所以空气阻力就很小,两样东西才会同时落地。 但如果这样子解释的话就无法解释为什么天空是蓝色的,而且太阳落山时还会出现红光。 所以我们得出结论:mc并不遵循自由落体定律。 但这或许还无法说服某些杠精,那么我们就再做一个实验: 假设一个矿车和一张未折叠的纸同时下落,谁会最先落地? 按理来说,矿车用铁做,下落速度肯定要比空气阻力大的未折叠纸要快,但实际上呢? 纸最先落地。 这到底是为什么? 其实关于mc实体的下落速度,有这么几个参数: 加速度、阻力和终端速度。 加速度,顾名思义,就是实体在固定时间所增加的下落速度,单位一般是m\/tick2或m\/sec2。 阻力,顾名思义,就是实体在固定时间所抵消的下落速度,单位一般是m\/tick?1。 终端速度,也就是最大下落速度,实体的下落速度都不会超过这个值,单位一般是m\/tick或m\/sec。 而我们的矿车,它的这三个参数是—— 加速度:16m\/sec2;阻力:0.05m\/tick?1;终端速度:15.2m\/sec 也就是说,我们的矿车,它的最快速度是每秒下落15.2米。 然后再来看看我们的纸: 加速度:16m\/sec2;阻力:0.02m\/tick?1;终端速度:39.2m\/sec 可以发现,矿车和纸的加速度都是相同的,但由于纸的终端速度比矿车的终端速度大了将近一倍,且纸受到的阻力还比矿车受到的阻力还要小(这就nm离谱),所以我们的矿车最终敌不过纸。 实际上,mc里的每个实体都有自己的加速度、阻力和终端速度,当然mojang可没有那么勤劳,会给mc里的每个实体都弄一个独一无二的下落参数。所以mojang是这样做的: 玩家和生物——加速度:32m\/sec2;阻力:0.02m\/tick?1;终端速度:78.4m\/sec 物品、下落的方块、tnt——加速度:16m\/sec2;阻力:0.02m\/tick?1;终端速度:39.2m\/sec 船和矿车——加速度:16m\/sec2;阻力:0.05m\/tick?1;终端速度:15.2m\/sec 扔出的雪球、鸡蛋、药水以及末影珍珠——加速度:12m\/sec2;阻力:0.01m\/tick?1;终端速度:60m\/sec 射出的箭——加速度:20m\/sec2;阻力:0.01m\/tick?1;终端速度:100m\/sec 火球、凋灵头、龙息球、潜影贝导弹——加速度:0m\/sec2;阻力:0m\/tick?1;终端速度:38m\/sec 相信看完了上面的这些数值,你应该已经总结了几条: 1.玩家和生物的下落最大速度(78.4m\/sec)是物品的下落速度的两倍 2.箭的下落最大速度是最快的(100m\/sec) 3.船和矿车的下落最大速度最慢(15.2m\/sec) 其中,第一条估计是最常用的。 在哪里常用呢?看那些网上秀操作的视频就有很多有用到这条。 没映象?相信我说一下他们是怎么做的你就想起来了: 他们会通过某种方式(一般是无缝剪辑)来到一个很高的地方。通常先把一个东西(一般是水桶)扔下去,然后跳下去,在这过程中他们通常会使用武器(一般是弓)击落几只安排好的动物(一般是猪、牛或羊),接着在半空中拿到刚才扔下去的东西,落到地上(如果是水桶的话通常是表演一下落地水),收工或者继续来个无缝剪辑。 想起来了吧?学完了上面这个后,或许你可以来个比半空接东西更高级的操作: 半空上船或车 听起来就是一个很棒的想法有木有?相信如果真拍出来观众不给个三连那是不可能的。 这就是实体的运动。但运动研究完了不代表本章就结束了。 接下来我们看看实体的历史发展: java: beta1.8——出现了一个bug:玩家能在创造模式中相隔很远甚至隔着方块都能和实体互动。 1.1——玩家不再能在创造模式下与远方的实体进行互动。 1.4.2 —12w34a——实体现在可以穿过传送门。 1.9 —15w31a——稍微更改了弹射物的运动机制。 —15w36a——大部分实体(物品和经验值除外)能够被另一个实体推动。 —15w45a——在一个1x1的洞中聚集的实体不再能推开接触相邻角落的实体。 —15w49a——玩家在坠落、使用鞘翅飞行或被击退时的动力现在会影响弹射物的运动轨迹,但在玩家步行、骑乘实体和在创造模式中飞行时除外 1.11 —16w32a——1实体id现在改成了下划线,没有大写字母。它们也能在id前面前面打下minecraft:,就像方块id那样。2人类的idmonster和拉娜、史蒂夫(生物)、黑史蒂夫和野兽小子的idmob被移除。 携带版(alpha): ?——生物的内部不再渲染。 携带版: 0.9.?——出现了和java beta1.8一样的bug(见上java beta1.8)。 基岩版: ?——生物的内部现在再次渲染。 了解了一点实体的历史,接下来我们进入这个章节最后的一部分: 易搞混的两个东西 这两个东西是什么?为什么会很容易搞混呢? 首先来解答第一个问题:这两个东西是什么? 这两个东西分别是实体方块和方块实体。 然后是第二个问题:为什么会很容易搞混呢? 这就要详细说了。 首先是名字,可以发现这两个东西的名字一个是“实体方块”,另一个是“方块实体”,仅差在这两个词是相反的排列顺序。 实体方块我们知道就是指实体状的方块,那么这个“方块实体”是什么东西? 实际上这个方块实体虽然有“实体”二字,也是“实体方块”的倒排列,但跟实体和实体方块是八杆子打不着的。方块实体指的并不是实体状的方块,也不是指方块状的实体,而是:方块储存的东西。 举个例子,我们在告示牌上写了一些文字,那么这些文字就是这个告示牌存储的东西,也就是“告示牌的实体”;我们在箱子里放的物品,这些物品也是这个箱子存储的东西,也就是“箱子的实体”。 所以以后,不要把实体状的方块叫做“方块实体”,而要反过来说成“实体方块”,避免产生歧义。 ok这一章就到这里了,下一章我们来了解一下实体中的一个大类——生物。 (又称:mc生物学[滑稽]) 第一百三十章 mc生物学 mc的生物[mobs]是什么? 你应该没有注意到,mc的生物其英文是“mobs”,这个单词在英文中是单词“mob”的复数形式。而mob在英文中的意思指的并不是生物,而是: n.人群;(尤指)暴民;一帮(有共同点的人);犯罪团伙 v.聚众袭击;围拢 web 暴徒;乌合之众;聚众闹事 总而言之mob这个意思就是: 名词——指暴民 动词——指暴动 好像跟生物八杆子打不着啊? 别着急,其实,在mc里,mob这个单词并不是指上面这两个意思,而是还有另一层意思: “mob”是英文单词“mobile”的缩写 哎,没想到吧,是个缩写。所以让我们来看看这个mobile \/?mo?b(?)l\/是什么意思: n.手机;汽车;移动电话;可动物体 adj.活跃的;可动的;流动的;可移动的 web 莫比尔;活动的 而在mc里,mob这个mobile的缩写单词,所取的意思就是: n.可动物体(注意,这个“可动物体”的断句是“可动\/物体) 这个“可动物体”也基本概括了mc里生物的基本特征: 会自主移动 这就是“生物”的基本定义。 所以以后,如果你用生物蛋生出来一只羊,因为你是一名中国人,所以这只羊就是一只“中国羊”,也就是“中国的生物”,即: china mobile 简称m 嗯,原来中国移动就是这只羊啊*。 (*注:中国移动的英文是china mobile) 现在我们知道该如何区分生物和其他实体了,那么接下来该干什么呢? 我们在上一章讲到了生物可以通过性格分为: ——被动生物 ——中立生物 ——攻击生物 ——boss生物 而被动生物还可以分为: ——和平型生物 ——防御型生物 上面的分类是按照生物的性格分类的,如果按照生物的生活环境以及特点可以分成什么呢? 答案很简单,可以分成: ——陆生生物(特点:1会溺水2生活于陆地上3怕岩浆;例子:羊、村民) ——水生生物(特点:1离开水过一会儿就会窒息死亡2生活于水中3怕岩浆4会游泳;例子:热带鱼) ——下界生物(特点:1怕水2免疫岩浆3生活于下界;例子:僵尸猪人、岩浆怪) ——末地生物(特点:1会瞬移;例子:末影人、潜影贝) ——两牺生物(特点:1不会溺水2不会窒息;例子:海龟) ——半水生生物(特点:1会溺水,但达成需要时间较长2会窒息;例子:海豚) 也可以分成: ——亡灵生物[undead mobs](特点:1受到治疗和伤害药水的效果是相反的2大部分会在阳光下燃烧3会被“亡灵杀手”附魔影响4在水下不会溺水[都死过一次了还会再死一次吗?]) ——节肢生物[arthropod](特点:1会被“节肢杀手”附魔影响2是蜘蛛、洞穴蜘蛛、蠹虫、末影螨和蜜蜂[真的,节肢生物就这么5个,所以节肢杀手这个附魔有多没用你应该知道了吧?]) ——灾厄村民[igers](特点:1外观与村民、流浪商人和女巫相似2与玩家、村民、流浪商人、雪傀儡[仅基岩版]和铁傀儡敌对) 上面这3个分类是minecraft的官方分类(所以都有英文翻译),虽然只是分类了一小部分生物,但也值得我们去记住。 (可惜苦力怕没有分类) 生物的分类我们就先分到这里(实际上也没什么可分的了),接下来我们来研究研究: 被动、中立和攻击这三种生物 我们知道被动生物可以分为和平型和防御型。和平型的被动生物有很多种,但防御型的生物只有一种——河豚。 为什么呢?因为河豚会在玩家靠近时给玩家中毒效果,但其并不想攻击玩家,只是属于“正当防卫”,所以算是和平生物。但由于其他和平生物都不会直接给其他生物造成伤害,所以只能给河豚单独画一个“型”了。 你可能注意到了,上面这句话中“其他和平生物都不会直接给其他生物造成伤害”有一个“直接”,那么如果不是直接造成其他生物伤害,是怎么样的呢? 这样子情况就很多了,比如: 1.玩家在悬崖边被一只羊推了下去。 2.26个村民掉到一个只有1x1x2的洞,由于超过了单实体所能推的实体的上限,导致这些村民集体受到了窒息伤害。 3.一只牛不小心触发了陷阱,把玩家给坑了。 ....... 然后是中立型。中立生物可以说是介于攻击生物和和平生物之间,它们大部分不会在和平模式出现,有些比如狼会出现在和平模式,但没有攻击伤害了。 中立生物的典型生物就是僵尸猪人,相信在座的各位没有一个是没被僵尸猪人给砍死过的吧?神奇的是,羊驼也是中立生物,可能就是因为它射出的口水有着半滴血的伤害(真的,别小看这半滴血,两个羊驼互喷可不是一件好玩的事情,它们会......亲在一起) ....... 最后是我们的攻击生物,攻击生物没有一个会在和平模式活下来,它们的典型特征就是会主动攻击玩家。僵尸是最典型的攻击生物,它有许多的变种: 僵尸猪人(下界)、尸壳(沙漠)、溺尸(水中)、小僵尸、僵尸村民 其中,尸壳、溺尸和僵尸估计是最亲的,因为它们: 尸壳在水里呆上一会变成僵尸 僵尸在水里呆上一会变成溺尸 嗯,仔细一想确实挺科学的。尸壳就是缺水的僵尸,僵尸渗进了更多的水就变成了溺尸。 神奇的是,mc最早的生物并不是和平生物,也不是中立生物,而是怪物(攻击生物)——人类 没错,这里指的人类就是那个一直按g就会源源不断凭空生成的活蹦乱跳史蒂夫。 真奇怪为什么那么可爱的史蒂夫怎么会是怪物呢? ok这一章就到这里了,下一章我们将会开始真正的讲nbt了。 第一百三十一章 生物的共通nbt-1 在第一百一十二章到一百一十三章这两章里,我详细地介绍了实体的通用nbt,或者说是实体的基础nbt。在此基础上,mojang又添加了一些新的nbt,这些新的nbt加上原来的实体nbt,就变成了: 生物的共通nbt 生物的共通nbt的内容相较于实体基础nbt增加了很多,以至于要用更多的篇幅去讲述它。当然这些并不一定要背下来,稍微了解个大概,需要用的时候过来看就行了。有时候用着用着说不定就记下来了呢!(当然,荒废一段时间还是会还回去的) 那么这些共通的nbt到底是什么呢? 我们知道,一个生物,最基础的就是血量,所以共通nbt自然而然就有血量: health(值:数值) 这个health就是生物的血量值。但如果你玩过游戏,应该就会知道一个生物的血量至少要有两个变量: 1.当前的血量 2.血量最大值 而这个health就是指当前的血量,比如现在有一只猪它有1滴血,它的nbt就是: {health:1} 但实际上,很多时候这个health并不是个整数,而是个小数(准确的来说是“浮点数”)。比如你徒手去攻击一位全是钻石套的大佬,你别看它的心数没变,就认为你的攻击没起到作用,实际上是因为伤害过小被约没了而已,因为这个大佬在受伤后的的health是: {health:19.} 你给这位大佬造成了0.0滴血的伤害,相当于这位大佬血量的3.‰ 嗯,确实够小的。 而有时候,health也可以达到负数,比如你一击就秒了对方,那么对方在临终前的血量就是: {health:-623.5} 嗯,这伤害都够同时秒末影龙和一只java版的凋零了。 而如果这个health的值超过了所允许的最大值,比如你通过修改器把自己的血量修改成了会怎么样? 答案是你进入游戏后就会拥有滴血,只不过这并没有什么卵用,因为当你遭受到了伤害,就算是一点点,游戏也会: 本次攻击共造成了0.00635滴血的伤害,正在扣除中 我靠,这家伙的血量怎么超过了这个生物属性里的generic.maxhealth*数值! (*关于generic.maxhealth早在第一百零五章时就讲到了,当时就已经讲到了生物的属性,建议忘记的同学赶紧回去复习一下) 不行,这家伙绝对开挂了!必须要干点什么。 也不知道这家伙在修改之前的生命值是多少。算了,直接改成允许的最大值吧! ——health的值从变成了20 ——health的值从20变成了19. 恭喜你,你的血量一夜回到了解放前! 所以说以后改血量的时候最好先把最大值改了,不然改个毛线。 上面说过,要弄血量至少需要两个变量。但mc作为一个十多年还在焕发活力的老游戏,只有两个血量的变量,未免有些奇怪。所以mc不只两个血量变量,而是还有: absorptionamount(值:数值) (哎作者,最大值还没讲呢!) 呃,其实早就讲过了,最大值其实就是一个属性,在第一百零五章时就讲过了。 absorptionamount的作用是指通过伤害吸收效果所获得的额外生命值,就是那个吃了金苹果生命值多了的那个黄色小心心。 为什么mojang要单独添加这个属性呢? 因为minecraft还有一个和伤害吸收作用很相似的效果:生命提升 但这只是表面相似,实际上生命提升是直接提升generic.maxhealth生命最大值,所以显示出来的是红心,而且掉了还可以回。伤害吸收就不一样了,那黄色生命是一次性的,生命最大值还是最大值,提升的实际上并不是生命,而是添加了类似于盾牌的效果,只不过抵挡的生命值是可以直观显示的。 所以,absorptionamount这个属性的作用是指能抵消的伤害量,并不是指提升的血量。 比如: {health:20,absorptionamount:4} 这样子显示成心的话将会是10颗红心+2颗黄心。 .......一个并不华丽的分割线...... “......看,红队那名玩家刚刚挖了蓝队的床,蓝队的那些成员都围在那红队的旁边。可以看到有一名胆小的蓝队跑了,虽然这看起来有些背叛其他人,但接下来那名红队玩家以一挡五,使用了单身起码15年的手速迅速地先干掉两名离他最近的蓝队,将其打下虚空。剩下那3名蓝队竟然没有溃逃,而是团结在了一起,重新像那红队发起进攻。红队那名玩家看动作应该是打算先虚张声势一下,趁蓝队恍惚间逃走,但没想到蓝队反应速度之快,将其打个措手不及,死亡......” 相信你一定玩过起床战争,就算没玩过也起码干过pvp或pve。在攻击敌方时,敌方受到攻击都会发红,这点在羊身上特别明显,一白一红的强烈反差述说着那羊的痛苦,以及引出了一个新的问题: 这个发红的时间是否有跟生物本身的nbt有关? 确实有关。 在生物的共通nbt里,有这么一个标签: hurttime 这个英文简直是太简单了,按照现在的神童标准出生不到一分钟就可以翻译了: 疼痛时间 这个疼痛时间其也是一个数值,存储着生物被击中后发红了多长时间,单位是刻。生物不红之后值返回0,即代表着:生物最近未被击中。如: {health:4.65,absorptionamount:0,hurttime:16} 说明这个生物发红已经持续16刻了。 这个标签是控制生物的发红时间的,我们不需要太深入研究。 而另外一个标签: hurtbytimestamp(值:数值) 和hurttime也与伤害有关,只不过这个标签记录的是“距离该生物上次受到伤害的时间”,单位也是刻,比如: {health:6,hurtbytimestamp:853,hurttime:0} 就说明该生物距离上次受到伤害已经过去853刻的时间了。 真的是这么理解的吗? 实际上还有另外一种理解方式: 就说明该生物距离生成或出生已经过去853刻的时间了。 没错,如果该生物这生还没受到伤害,那么这个值将会记录它已经出生或生成多久了。 而当该生物死亡了呢? 如果这个生物不是玩家的话,那就没了。 但如果是玩家,实际上生物的共通nbt里有这么一个标签: deathtime(值:数值) 这对于生物本身没什么用,但它在玩家的nbt里就有用了——它记录者玩家距离上次死亡多久了,主要是用于控制死亡动画,单位当然也是刻。 这个标签我们当然不需要深究,但我们却可以思考一个问题: 为什么生物的nbt里有这个玩家才用得到的标签呢? 答案很不简单,作者猜是这样的: 上古时期(java-ssic),贫瘠的minecraft迎来了第一个生命——人类。这个神奇的生物不会饥饿,不会口渴,更不会死亡。它们会在世界里乱跑,乱跳。正是因为它们的存在,minecraft才出现了树、史蒂夫、羊、牛、鸡等物种,给这片本来贫瘠的大地带来勃勃生机。 (哎作者,minecraft的第一个生命不是草吗?) 所以玩家是由生物进化而来的,自然而然玩家就遗传了生物的dna(nbt)。 嗯,这样子就解释得通了。 ok生物的共通nbt就先讲到这,我们下章再见! 第一百三十二章 生物的共通nbt-2 在上一章的末尾,我们发现玩家和生物其本身的nbt很多是互通的。所以,你能在生物的共通nbt中找到一些玩家身上也有的nbt。 比如:fallflying(值:布尔值) fallflying是个布尔值,一般来说它是0。如果是1,生物(或者是说“非玩家实体”)就会像用鞘翅滑翔般滑翔起来。而如果是玩家,那么玩家当然是在滑翔时这个值才会是1,所以fallflying被用于检测一个玩家是否在滑翔。 那么这到底有什么用呢? 或许就是让非玩家实体滑翔起来吧,或者是用于服务器防飞行挂的鞘翅飞行检测,防止误判。 这是一个玩家和生物nbt互通的例子,而在生物的共通nbt中,还有很多这样的例子,比如这三个: sleepingx(值:数值) sleepingy(值:数值) sleepingz(值:数值) 这三个标签并不是时时刻刻都会出现,因为这三个标签的作用是: 记录实体当前正在睡觉的床的坐标 为什么还要记录呢?直接使用实体本身的坐标不行吗? 肯定不行,因为mc是一个充满特性的世界。如果你哪天在mc里睡觉,没想到触发了一个特性,让你飘离床,在飞天神曲的沐浴下经过了流沙河,翻越了火焰山,到达了西天大雷音寺这样子在睡梦中完成了西天取经的十万八千里。然后你醒来了,如果游戏就是采用直接使用实体本身的坐标的话,那么—— “我是谁?我在哪?我在干什么?” (过了一会) 这时东土大唐边境河州卫,玄奘正要离开驿馆。突然观音菩萨出现在玄奘面前,告诉他有人已经提前一步拿到了大乘佛法了。 玄奘:......... 所以mojang为了避免这种情况的发生,使用了在玩家睡觉的时候就记录床位置的方法,这样子就算玩家飘离了十万八千里再起来: “啊~又是新的一天啊。” “应该给自己的豪宅再升级一下了。” (于是玩家挖了几块泥土) “真不错。” 所以这三个标签是极其重要的。 只不过生物会睡觉吗?好像只有村民会哦。 比如现在这里有个村民,他睡在x=564,y=87,z=65这个床上,那么他这个时候的这三个值就是: { sleepingx:564, sleepingy:87, sleepingz:65 } ——————一个很不华丽的分界线——————— 在上一章我们讲到,生命的最大值其实就是一个属性。如果我们要修改这个属性,该怎么办呢? 生物的共通nbt里就有这么个标签: attributes(值:列表) 这是一个列表,所以它的值是这样的: {attributes:[a,b,c]} 那么这些abc该填什么? 答案是属性: {attributes:[{a属性},{b属性},{c属性}]} 既然是属性,我们就不妨复习一下一百零五章的属性修饰符: “{attributemodifiers:[{}]} 在这个文件夹里,有这么几个文件,需要我们修改一下(记得去“*”号): attributename*——要修改的属性id name*——要修改的属性名字 slot*——指定生效的槽位 operation*——属性数值是怎样运算的 amount*——属性数值 uuidmost*——这个属性uuid的高位 uuidleast*——这个属性uuid的低位” 可以发现,当时讲到的属性修饰符,里面有很多个标签。 但别忘了,属性修饰符是属性的修饰符啊,我们现在才深入到属性啊,所以我们得先看看一个属性需要几个标签: name——属性的名称 base——属性的基础值 modifiers——属性的修饰符 只有三个,看起来非常简单。实际上也非常简单,比如我们的生命最大值,它就是这样的: {attributes:[{name:“generic.max_health“,base:20}]} 我们要修改,除了给这个属性添加修饰符,还可以直接把base值修改。 那么base可以修改到什么程度呢? 这个base值的类型是“双精度浮点型”,比我们上一章提到的“单精度浮点型”高级了一倍。 注意,这里的“高级了一倍”不是作者自己猜的,而是有实际依据的,因为: 单精度浮点型——占用空间:32位(4字节) 双精度浮点型——占用空间:64位(8字节) 占用空间增加了一倍,确实是高级了一倍。 但如果按照这样子说的话,64位系统岂不只是32位系统的两倍? 那肯定是不对的。所以我们的这两个浮点型,它们虽然占用空间是两倍的关系,但实际可储存的数值是: 单精度浮点型——取值范围:-3.4e38~3.4e38 双精度浮点型——取值范围:-1.e308~1.e308 嗯,确实,是高级了亿倍.......好像还不止 所以,其实你的生命值上限最高并不是2048,也不是,而是: 1.x3081?! 所以,你还敢说你的创世之刃是能秒杀一切的武器了吗? 剩下的modifiers就很简单了,因为我们早在第一百零五章就讲到了。只不过这里的modifiers有些不一样,它只剩下了四个参数(1.16及以上5个): name——要修改的属性名字 operation——属性数值是怎样运算的 amount——属性数值 uuidmost——该修饰符的uuid高位 uuidleast——该修饰符的uuid低位 (1.16版本uuidmost和uuidleast合并成了uuid) 具体的用法就不再细说了,自己去一百零五章看吧。 (似乎篇幅不够,再来一点吧) 接下来的标签是: handitems(值:列表) handitems很容易理解,就是生物拿着的东西。又因为mc的生物都是有两只手的(你跟我说史莱姆有手?),所以handitems的列表是固定两个项目,一个主手,一个副手: {handitems:[{主手},{副手}]} 而这个主手和副手内填的就联系到我们的物品共通标签了: count——物品数量(值:数值) id——物品id(值:字符串) tag——物品的额外标签(值:复合标签——{}) 具体的我就不再讲了,已经讲了很多次了,况且才4个标签(还有一个slot),非常简单,傻子都能记住。 举个例子,比如村民的主手正拿着一个面包,那么他的handitems值就是: {handitem:[{count:1,id:“minecraft:bread“}]} 灰常简单是不是? 但如果这个村民拿着这个面包就被杀死了(哦天呐!),掉落这个面包的几率是多少呢? 虽然我们不知道几率是多少,但我们可以更改几率,这样子我们就知道了! 控制村民的手中物品掉落几率的标签是: handdropchances 这也是个列表,也有两个项目,分别代表着主手和副手掉落物品的几率。 这个几率的值是单精度浮点型,所以如果你想更改主手和副手掉落物品的几率为78%的话,那么需要这么改: {handdropchances:[0.78,0.78]} 这样子就可以了,还是灰常简单的。 ok这一章我们就先讲到这,我们下一章再见! (不知不觉国庆就已经过完一半了啊.......) 现在是中午12点整,王五和赵六正坐在橡木楼梯上刷b站。突然王五像触电似的站了起来:“wo cáo?” “发生了什么事?”赵六瞟了一下王五,继续看敖厂长的新视频。 “wo\bcào!”王五突然又叫了一声。 “哎你能不能别......”赵六话还没说完,王五又来了第三声:“wo\bcào太棒了!” “你老是卧槽卧槽干什么啊?”赵六决定看看王五到底在看什么,于是把头伸了过去。 “wo cáo?” “wo\bcào!” “wo\bcào太棒了!” 只见那个视频的标题是: 《洞穴更新成了!minecraft 1.17 更新特性汇总!洞穴与峭壁更新!》 第一百三十三章 生物的共通nbt-3 在上一章我们讲到了handitems和handdropchances,这两个标签都跟生物的两只手有关。而一个生物,它不光拥有手,还拥有一个可以穿戴东西的身体。 所以,nbt里除了handitems,还有armoritems——用于存储生物的头、胸、腿、脚都穿了些什么鬼东西。 armoritems的值和handitems一样,都是列表。列表内有4个空,分别用于填写四个部位所穿戴的物品: {armoritems:[{靴子},{护腿},{胸甲},{头盔}]} 举个例子,现在这里有个僵尸,它头上戴着皮革帽子(leather_helmet),胸前穿着锁链胸甲(leather_chestte),腿上是个附了保护i的的钻石护腿(diamond_leggings),脚上穿着铁靴子(iron_boots),那么这个僵尸的armoritems就是: {armoritems:[{count:1,id:“iron_boots“},{count:1,id:“diamond_leggings“,tag:{enchantments:[{id:“protection“,lvl:1}]}},{count:1,id:“leather_chestte“},{count:1,id:“leather_helmet“}]} 哦不!这个僵尸死了!那么它掉落身上装备的几率是多少呢? 我们不知道有多少,但我们可以更改成自己想的,这样子就知道了! 和handitems一样,armoritems标签也有一个控制掉落几率的亲兄弟:armordropchances,格式和handdropchances当然也差不多,都是: {armordropchances:[靴子掉落几率,护腿掉落几率,胸甲掉落几率,头盔掉落几率]} 这里的几率也照样是单精度浮点数。举个例子: {armordropchances:[1.0,0.32,0.65,0.99]} 这样子的话这个僵尸其装备的掉落几率就是: 靴子——100% 护腿——32% 胸甲——65% 头盔——99% 是不是灰常简单? 当然,别忘了,击杀一个生物,掉落的不光是它拿的东西以及穿的东西,还有这个生物的战利品表所规定掉落的物品。 控制生物战利品表的标签就是:deathloottable,这个的值是个字符串,所以它填的战利品表一般是游戏已经封装好的,比如这个僵尸,它的默认战利品表就是: {deathloottable:“loot_tables\/entities\/zombie“} 也就是僵尸的战利品表。 当然,你也可以自定义战利品表,只不过你可能需要用到很多的转义符号(\\)。 具体的战利品表介绍已经在第八十九章就详细的讲过了,只不过好像很多人都没看懂哎。 没事,没看懂很正常,6000多字的内容可不是一时半会能消化得完的。 战利品表是随机的,但这个随机并不是战利品表自身的,而是要通过种子来完成: deathloottableseed deathloottableseed的用途是生成战利品表的种子,当为0或为空时将会随机生成一个种子。 上面的deathloottableseed和deathloottable都是关于战利品表的。但如果一个生物没有战利品呢? 除了它的战利品表是loot_tables\/empty外,还有一种可能: 它没有deathloottableseed和deathloottable这两个标签。 没错,实际上这两个标签是可选的,就算把它两删了也不会出什么惊天大事的。 但下面这个,就不能删了: canpickuploot(值:true|fasle布尔值) canpickuploot这个标签控制着这个生物它到底会不会捡起物品(或者说是战利品)。当为true,这个生物就会捡东西,然后把可以用的东西用起来,比如捡起靴子就穿上靴子之类的——这点在僵尸上特别突出:相信你应该经历过苦力怕把你箱子炸了,僵尸紧接着跑过来把你东西拿了,我都怀疑这苦力怕是不是和这僵尸心有灵犀,咋配合得这么默契呢? 所以,如果你不想让僵尸拿起你的剑去砍你,就把这个canpickuploot改成false吧! 生物的共通nbt还有许多和canpickuploot一样是布尔值的标签,且都很简单: noai(值:true|fasle布尔值)——这个生物是否没有ai。true为没有ai,false为有ai。 persistencerequired(值:true|fasle布尔值)——这个生物是否不会被自然删除。true为不会被自然删除,false为会被自然删除。 lefthanded(值:true|fasle布尔值)——这个生物渲染的主手是否为左手。true为渲染时主手为左手,false为渲染时主手为右手。 leashed(值:true|fasle布尔值)——这个生物是否被拴住。true为被拴住,false为没有被拴住。 而其中,最复杂的应该要数leashed。当这个为true时,就会有一个新的标签: leash 这个leash稍微有点复杂,它有两种记录方式: 1.该实体为拴绳的头(没错,就是栏杆上那个长方形状的拴绳头,那也是个实体)或拿着拴的实体,那么将会记录它拴住的实体的uuid(1.15版本及以下是uuidmost和uuidleast),即: {leash:{uuid:[i;-,,-,]}} (1.15版本及以下: {leash:{uuidmost:-,uuidleast:-}}) 2.该实体为被拴住的生物,那么将会记录拴住它的拴绳头或拿着拴着它的绳子的实体位置,即: {leash:{x:921,y:65,z=343}} 嗯,还是挺简单的。 到目前为止,我们已经了解了大部分生物的共通nbt,只剩下了三个没讲的了: team(值:字符串) brain(值:复合标签{}) activeeffects(值:列表[]) 其中,team是这里面最简单的。但是它的作用并不是存储这个生物所加入的队伍,而是: 如果team的值里面有填东西,该生物将会自动且立马加入team所填的队伍,加入后自动清空team的值。 所以这个标签实际上并不是个生物的nbt数据,而是方便在创建生物时让生物加入队伍。 所以这个标签的用武之地就是—— 实现起床战争召唤自家队伍的铁傀儡! ........ 然后是activeeffects。brain最复杂,我们留最后。 activeeffects的作用是存储这个生物所有的状态效果。如果这个生物没有状态效果,就不会有这个标签。 activeeffects的格式是这样的: {activeeffects:[{效果1},{效果2},{效果3},...]} 而这个效果,就要涉及到——效果的nbt(效果没有共通之说,因为效果的nbt都是一样的): id——效果id(值:数值) amplifier——效果等级,实际等级是这里的数值加上1。如这边填0,等级将是1(值:数值,范围:0~255) duration——距离效果消失的时间刻数。或者说是效果的剩余时间,单位为刻(值:数值[int整型]) ambient——这个效果是否是信标施加。如果是由信标施加,则为true,将会减弱粒子效果。不是则为false(值:true|fasle布尔值) showparticles——是否显示粒子效果。显示则为true,不显示则为false(值:true|fasle布尔值) showicon——是否显示效果图标(这个挺有用,配合showparticles可以神不知鬼不觉给人附上效果,比如用于起床战争)。显示图标则为true,不显示为false。(值:true|fasle布尔值) hiddeneffect——相同类型但效果等级更低的效果,将会暂时放在这边。如果上面的状态效果失效将会立刻取代它。当然,存在这边的效果剩余时间仍然会减少。(值:复合标签{}) 都懂了吧?这已经说得很详细了。举个例子,假设一个村民被玩家使用指令施加了110级时长3分30秒的跳跃提升,那么这个村民的activeeffects将是: {activeeffects:[{id:8,amplifier:109,duration:4200,ambient:“false“,showparticles:“true“,showicon:“true“}]} 但如果这时候玩家又给这个村民添加一个相同类型的状态效果,但等级达到了120级,时长只有1分钟,将会怎么样? 这时候就要了解一下hiddeneffect标签里的东西了,实际上还是一样的: id amplifier duration ambient showparticles showicon hiddeneffect 可以发现这里又有hiddeneffect。没错,确实是可以套状态效果的,想套多少都可以。 所以这时候村民的activeeffects就成了: {activeeffects:[{id:8,amplifier:119,duration:1200,ambient:“false“,showparticles:“true“,showicon:“true“,hiddeneffect:{id:8,amplifier:109,duration:4200,ambient:“false“,showparticles:“true“,showicon:“true“}}]} 懂了吧?其实灰常简单的。 最后就只剩下brain(值:复合标签{})了。 brain相当于这个生物的记忆,所以很高级。高级到什么程度呢?在生物里,到1.16,只有村民和猪灵有记忆。 brain的内容只有一个: memories(值:复合标签{}) 而memories的值,就多了: minecraft:meeting_point minecraft:home minecraft:job_site minecraftst_slept minecraftst_woken minecraftst_worked_at_poi minecraft:angry_at minecraft:admiring_item minecraft:admiring_disabled minecraft:hunted_recently 只不过这些内容,由于太多了,我们只好放到下一章再来讲了。 第一百三十四章 生物的共通nbt-4 上一章讲到生物的共通nbt的最后一个: brain 而这个brain里面的memories就是存储记忆的地方。记忆有这么几个: minecraft:meeting_point——这个村民聚会的位置 minecraft:home——这个村民床的位置 minecraft:job_site——这个村民工作的地方(就是这个村民的工作站坐标) minecraftst_slept——这个村民已经睡觉多长时间了 minecraftst_woken——这个村民已经多久没睡觉了 minecraftst_worked_at_poi——这个村民多久没工作了 minecraft:angry_at——这个猪灵的目标 minecraft:admiring_item——这个猪灵端详物品的状态 minecraft:admiring_disabled——这个猪灵拿起物品端详这个技能的冷却状态 minecraft:hunted_recently——这个猪灵追猎这个技能的冷却状态 这些记忆都带有“minecraft:”,说明mod也可以对记忆进行增加。 其中,6项都是村民的,剩下4项都是猪灵的。 现在我们来看第一项记忆: minecraft:meeting_point——这个村民聚会的位置 这个记忆是个复合标签({}),实际上所有记忆都是复合标签: {brain:{memories:{minecraft:meeting_point:{}}}} 里面只有一个标签value(值:复合标签): {......:{minecraft:meeting_point:{value:{}}}}} (老套复合标签了啊) value里有这么几个参数: pos(值:列表)——聚会地点的x、y、z坐标 dimension(值:字符串)——聚会地点的纬度id {......:{minecraft:meeting_point:{value:{pos:[x,y,z],dimension:“纬度id“}}}}} 现在我们举个例子,比如这个村民它的聚会场所是在主世界的x=45,y=77,z=1862的地方,那么它的这项记忆就将是: {......:{minecraft:meeting_point:{value:{pos:[45,77,1862],dimension:“0“}}}}} 是不是很简单?对了,这里的纬度id也就是世界id,主世界的世界id是0,下界是-1,末地是1(好像讲过了哎)。 minecraft:home(这个村民床的位置)的格式和minecraft:meeting_point几乎一样,都是: {......:{minecraft:home:{value:{pos:[床的x,床的y,床的z],dimension:“床的纬度“}}}}} 比如一个村民的床在下界的x=45,y=87,z=106的位置,那么: {......:{minecraft:home:{value:{pos:[45,87,106],dimension:“-1“}}}}} 嗯。对哦,村民在下界睡觉床不会爆炸吗? 还真的不会爆炸(奇怪的知识增加了!)。 既然minecraft:home的格式和minecraft:meeting_point几乎一样,而minecraft:job_site(这个村民工作的地方)也是记录着坐标,所以minecraft:job_site实际上格式也和前面两个一样: {......:{minecraft:home:{value:{pos:[工作方块x,工作方块y,工作方块z],dimension:“工作方块的纬度“}}}}} 举例子就不用举了,都懂。 然鹅接下来这三个就不一样了: minecraftst_slept——这个村民已经睡觉多长时间了 minecraftst_woken——这个村民已经多久没睡觉了 minecraftst_worked_at_poi——这个村民多久没工作了 它们都是存储时间的,所以格式就和之前三个存储坐标的不一样。但既然它们都是存储时间的,所以它们的格式....... 没错!它们三的格式也是完全一样的。比如minecraftst_slept(这个村民已经睡觉多长时间了)的格式是这样的: {......:{minecraftst_slept:{value:时间(单位:刻)}}}} 举个例子,假设这个村民已经睡了2个小时了(村民:?),那么这个村民的这个记忆的值就是: {......:{minecraftst_slept:{value:}}}} 代表着这个村民已经睡了刻了,也就是120分钟,即两小时。 而我们已经知道了minecraftst_woken(这个村民已经多久没睡觉了)和minecraftst_worked_at_poi(这个村民多久没工作了)格式都和minecraftst_slept一样,所以: minecraftst_woken格式—— {......:{minecraftst_woken:{value:这个村民没睡觉的时间(单位:刻)}}}} minecraftst_worked_at_poi格式—— {......:{minecraftst_worked_at_poi:{value:这个村民没工作的时间(单位:刻)}}}} 至于举例子嘛......这么简单就不用举了,况且格式都一样。 接下来就是猪灵了。猪灵一共有4个记忆,即: minecraft:angry_at——这个猪灵的目标 minecraft:admiring_item——这个猪灵端详物品的状态 minecraft:admiring_disabled——这个猪灵拿起物品端详这个技能的冷却状态 minecraft:hunted_recently——这个猪灵追猎这个技能的冷却状态 这四个标签的内容,都有一个“ttl”标签。这个标签的值是数值,实际作用就是: 这项记忆还有多久消失(单位:刻) 又或者可以说是: 猪灵的技能冷却剩下时间(单位:刻) 当然,具体的作用会根据不同的记忆会出现一些出入。 第一个minecraft:angry_at(这个猪灵的目标),它的值有两个: value(值:uuid整形数组) ttl(值:数值) ttl刚才说过了。这个value存储着uuid,再联系一下“目标”,你想到了什么? 这个value填的就是猪灵的目标实体的uuid! 嗯,没错。现在我们举个例子,假设这个猪灵已经锁定了一个uuid为[i;-,,-,-]的凋零骷髅,而且距离这个猪灵忘记这个凋零骷髅的时间还有1分57秒,那么其这项记忆就是: {......:{minecraft:angry_at:{value:[i;-,,-,-],ttl:2340}}}} 嗯,除了uuid有点长之外,其他都挺简单的。 然后是minecraft:admiring_item(这个猪灵端详物品的状态)。其值也有两个: value(值:布尔值) ttl(值:数值) 这里的value是布尔值,也就是true和false。如果是true,那么就代表着这个猪灵在端详物品。false则不是。 ttl在这里的作用是:端详还剩下的时间(单位:刻) 举个例子,比如一个猪灵它正在端详,且剩下的端详时间还有7秒,那么其这项记忆就是: {......:{minecraft:angry_at:{value:“true“,ttl:140}} 接着是minecraft:admiring_disabled(这个猪灵拿起物品端详这个技能的冷却状态)。其值仍然有两个: value(值:布尔值) ttl(值:数值) 既然是冷却状态,我们就得了解一下“猪灵”其“端详”这个技能的冷却会因为什么而触发。一共有3种触发方式: 1.正在转化成僵尸猪灵 2.受到伤害 3.使用完了”端详”这个技能 当上面3个条件的任意一项达成时,“端详”技能将会进入冷却。同时,该记忆也将会改变。 value在这条记忆里的作用是: 当值为true,代表“端详”技能处于冷却状态。当值为false,代表“端详”技能可以使用。 ttl在这条记忆里的作用是: “端详”技能的剩余冷却时间(单位:刻) 举个粒子。假设一个猪灵刚刚端详完成,其“端详”技能已经进入冷却状态,冷却时间为8.4s,那么这个记忆就将是: {......:{minecraft:admiring_disabled:{value:“true“,ttl:168}} 懂了吧?懂了就下一个:minecraft:hunted_recently(这个猪灵追猎这个技能的冷却状态) 和minecraft:admiring_disabled一样,这也是技能的冷却。但这次的技能是“追猎”。 首先,minecraft:hunted_recently仍然有这几个值: value(值:布尔值) ttl(值:数值) 然后,“追猎”技能会在出现以下任何一种情况都会冷却: 1.使用完“追猎”技能 最后,这里的value当为true时,就代表着“追猎”技能正在冷却。为false,就是可以正常使用。ttl跟minecraft:admiring_disabled一样,也是技能冷却的剩余时间。 举个栗子:假设一只猪灵刚刚追猎完成,其“追猎”技能已经进入冷却状态,冷却时间为1m24s,那么这个记忆就将是: {......:{minecraft:hunted_recently:{value:“true“,ttl:1680}} 是不是简洁明了? 所以,这就是原版brain的全部内容。 太棒了!生物共通nbt终于完了! ...... ——生物共通nbt: 包含所有实体共通nbt health——生物当前生命值。值:浮点数 absorptionamount——生物可抵消攻击的值。值:浮点数 hurttime——生物已经发红的时间,单位刻。值:整数 hurtbytimestamp——生物距上次受到伤害的时间值,或是距生成的时间值,单位刻。值:整数 deathtime——距生物死亡的时间刻数。值:整数 fallflying——生物是否滑翔。值:布尔值(1 or 0) sleepingx——生物正在睡的床x坐标。值:整数 sleepingy——生物正在睡的床y坐标。值:整数 sleepingz——生物正在睡的床z坐标。值:整数 brain——生物的记忆。值:复合标签({}) ——memories——值:复合标签({}) attributes——生物的属性。值:列表([]) ——一个属性——值:复合标签({}) ————name——属性名称id。值:字符串 ————base——属性基础值。值:浮点数 ————modifiers——属性修饰符。值:列表([]) ——————一个属性修饰符——值:复合标签({}) ————————name——修饰符的名称,可随便。值:字符串 ————————amount——修饰符调整属性基础值的数值。值:浮点数 ————————operation——修饰符对属性修饰符调整的基础算法。值:整数 ————————uuid[1.16版本及以上]——修饰符的uuid,用于区分修饰符。值:整形数组([i;1,2,3,4]) ————————uuidmost[1.16以下]——修饰符的uuid高位,用于区分修饰符。值:整数 ————————uuidleast[1.16以下]——修饰符的uuid低位,用于区分修饰符。值:整数 activeeffects——生物所有的状态效果。值:列表([]) ——一项状态效果——值:复合标签({}) ————状态效果nbt(见第一百三十三章) handitems——生物手持的物品。值:列表([]) ——主手手持物品——值:复合标签({}) ————物品共通nbt(见第一百零八章) ——副手手持物品——值:复合标签({}) ————物品共通nbt(见第一百零八章) armoritems——生物穿在身上的物品。值:列表([]) ——脚上穿的物品——值:复合标签 ————物品共通nbt(见第一百零八章) ——腿上穿的物品——值:复合标签 ————物品共通nbt(见第一百零八章) ——胸前穿的物品——值:复合标签 ————物品共通nbt(见第一百零八章) ——头上戴的物品——值:复合标签 ————物品共通nbt(见第一百零八章) handdropchances——手持物品掉落几率。值:列表([]) ——主手物品掉落几率。值:浮点数 ——副手物品掉落几率。值:浮点数 armordropchances——盔甲掉落几率。值:列表([]) ——靴子栏物品掉落几率。值:浮点数 ——护腿栏物品掉落几率。值:浮点数 ——胸甲栏物品掉落几率。值:浮点数 ——头盔栏物品掉落几率。值:浮点数 deathloottable——生物战利品表。值:字符串 deathloottableseed——生成战利品表的种子。值:整数 canpickuploot——生物是否可捡起战利品。值:布尔值(true|false) noai——生物是否没有ai。值:布尔值(true|false) persistencerequired——生物是否不会自然消失。值:布尔值(true|false) lefthanded——生物是否渲染时的主手为左手。值:布尔值(true|false) leashed——生物是否被拴住。值:布尔值(true|false) team——生物要加入的队伍,这实际上不是生物的nbt。值:字符串 leash——这里说不清楚,具体见第一百三十三章。值:复合标签 ——uuid[1.16及以上]——被拴住的生物的uuid。值:整形数组 ——uuidmost[1.16以下]——被拴住的生物的uuid高位。值:整数 ——uuidleast[1.16以下]——被拴住的生物的uuid低位。值:整数 ——x——拴绳的位置的x坐标。值:整数 ——y——拴绳的位置的y坐标。值:整数 ——z——拴绳的位置的z坐标。值:整数 第一百三十五章 真正深入了解nbt-1 在之前的第一百章——“深入地了解一下nbt”中,其中的80%都有水的成分。所以今天,我们就真正深入地了解一下nbt。 ——第一节:nbt的格式 在之前,我们已经讲了很多nbt。这些nbt内容都不一样,但它们都有一个共同点: 最外层都是使用“{}”包裹起来的。 没错,nbt和json的格式并不一样。json最外层使用“[]”和“{}”都可以,nbt却只能使用“{}”。 这是nbt的基本格式。 而nbt里面,是由n个标签组成的。每个标签之间必须用英文的半角逗号来区分。标签里包含标签名称和值,它两使用英文的半角冒号分隔: {标签:值,标签:值,标签:值} (注:阅读平台会自动把半角改成全角,所以这里的符号是全角符号,实际上在写的时候是全是半角) 而这个标签中的标签名称,它不是什么都能写的,而是有一个规则: 1.标签名称中只能出现字母a-z和a-z、数字0~9、下划线“_”。 2.标签名称中不允许出现空格(空格都以下划线替代)、中文以及特殊符号 3.标签名称对大小写敏感。 当违反了上述规则的时候,就会报错(或者是被游戏理解为另外一种意思)。 而标签的值,大家应该都知道标签的值类型是同标签中的标签名称或由另一个标签决定的,所以不同的标签名称,填的值格式都是不同的。 但实际上,值并不是直接写上内容就行了。当标签名称决定值的类型为特定类型时,值实际上还会有一个可填可不填的格式,我们待会就会讲到。 ——第二节:nbt数据类型 在之前,我们已经提到了很多nbt数据类型的名词: 单精度浮点型 双精度浮点型 整形(整数) 复合标签({}) 列表([]) 整型数组([i;1,2,3,4]) 字符串 可以发现,nbt的数据类型和json的并不一样,而且类型还比json多。 其实并不是类型多,而是nbt的类型分得比较细,实际上你搞个分类,就和json差不多了。 好的,现在请你拿出你的笔记本,并坐好,做一下心理准备,我们的车马上就要开动了! 3 2 1 go! nbt一共有14种数据类型,分别是: [字符] 字符串(string) [数值] {整形} 字节型(byte:b) 短整型(short:s) 整型(int:i) 长整型(long:l) {浮点型(小数)} 单精度浮点型(float:f) 双精度浮点型(double:d) [数据] 复合标签(pound) 列表(list) [数组] 字节型数组(byte array:[b]) 整型数组(int array:[i]) 长整型数组(long array:[l]) 我们从字符串(string)这个最简单的类型入手。众所周知,字符串类型的值其外层需要使用英文的半角双引号(““)来包括。当引号里的值要写上引号时,就需要使用转义符号(\\)放在引号前面转义。要在里面写上反斜杠(\\)时也一样。比如: {text:“我叫\\“小明\\“,这是反斜杠:\\\\“} 你知道吗?其实nbt的字符串并不一定需要使用双引号来包括,单引号也可以,只不过这是1.14版本才更新的: {text:''我叫\\''小明\\'',这是反斜杠:\\\\''} 如上面这个例子,要在值里面写上单引号,也是需要使用转义符号(\\)的。 而这个字符串还远远不止那么简单。字符串的存储上线是个字节,可以含有中文、空格和特殊字符,编码形式为utf-8。所以这就是为什么命令方块其字符上限就是,因为这就是字符串类型的值上线了。 只不过我们都知道,就连最基础的汉字也要占用2字节的空间,而utf-8作为万国码,存储的字符就更多了。所以utf-8的基础汉字一个就是3字节,而字符串的上限是字节,并不是个字符。所以更准确的来说,命令方块的储存上限是: 字节(utf-8编码) 而不是个字符,这种说法是错误的。 总之,字符串的特性就是: 1.值大小上限为字节 2.使用utf-8编码 3.文本可含有中文、空格和特殊字符 4.需用双引号(““)或单引号('''')(1.14版本及以后)包裹。 5.如需要在文本里写上引号或反斜杠,需在其前面加上转义符号(\\) 然后是我们的数值: {整形} 字节型(byte:b) 短整型(short:s) 整型(int:i) 长整型(long:l) {浮点型(小数)} 单精度浮点型(float:f) 双精度浮点型(double:d) 可以发现,nbt的数值细分到了整数和浮点数(小数)。我们先从整数入手,整数类型的类型有: 字节型(byte:b) 短整型(short:s) 整型(int:i) 长整型(long:l) 实际上这些都是存储整数。它们的明显差别只不过是名字的不同和数值上下限的不同。 最小的字节型(byte:b),其值是存储一个绝对值很小的整数,范围是: -128~127「-(2?)~2?-1」 很简单对吧? 其实不简单。在第一节的最后,作者提到特定类型的值还有可填可不填的格式。这个字节型就是其中之一,其格式其实是这样的: {byte:数值b} 没错,字节型的值需要你在填完数值之后再加上一个特定的字母,通常是这个类型其英文缩写的小写形式,比如字节型的byet缩写就是b,再小写一下就是b。 为什么要这样呢?其实这就是起到一个区分的作用,实际上你不在最后面写b也是可以的,游戏大部分情况会自动帮你加上去。当出现错误时可能才需要用到。短整型和长整型以及其他的一些类型也是数值后面有类型字母的,当然大部分情况它们不填也是可以的。 实际上byte类型值不仅仅是个数值,它还有另一种值: 布尔值(false|true) 没错,byte值也是布尔值,这个布尔值一般是数字形式的: 1和0 也有些情况下是true和false。 当为字母形式时,就不用填最后的b了,只需要类似于字符串那样加上引号就可以了(好像不加也可以)。 这就是byte类型。按理来说一个普通的mc指令教程说到这就可以了,但这本书并不普通。所以接下来我们要研究一个问题: 为什么这个值类型叫做“字节型”呢? 其实答案很简单。刚才的数值范围大家也都知道,是: -128~127, 也就是-(2?)~2?-1(二的七次幂的相反数到二的七次幂减一的差) 我们的一个字节,也就是: 8bit(8个二进制数字) 字节型数值的绝对值最大值是128,即2?,转换成二进制就是,刚好一字节。 这就是字节型这个名称的由来,是不是灰常简单? 总之,字节型(byte:b)的特性就是: 1.值为整数或布尔值 2.当值为数值时,数值范围为-128~127 3.当值为数值时,需要在值最后加上类型字母b 4.占用空间只有1字节 (唉,为什么最大值不是,即511?) (有补码懂不懂?有补码才能区分正负!) 比字节型范围稍大的短整型(short:s),在上面就有提到其也是有类型字母的。而这个类型字母就是:s,具体这个放在哪里大家都应该知道的。 短整形的数值范围是: -~「-(21?)~21?-1」(占用2字节) 是不是很熟悉?没错,1.13版本以下附魔的等级值就是短整形,所以当时的附魔最大等级才是。 所以我们可以根据这个附魔的标签来举个例子: {ench:[{lvl:s,id:18s}]}——这就是短整形的最大值,也就是附魔等级的最大值 {ench:[{lvl:-s,id:18s}]}——这就是短整形的最小值,也是附魔等级的理论最小值(lv.-?) (细心的朋友可能注意到了,1.13以前的id其值也是短整形) 到了1.13以后,情况就不一样了。mojang把lvl值类型改成了int整形,附魔的上限也就升级到了。但实际上,在新版本,lvl其值是int和short混用的。具体是这样的: 用附魔台附魔或战利品表生成的,是short短整形,但是读取时是按照int整形的时候来读取的。其他的就直接是int了。 只不过这些东西,我们以后再说。现在回到正题。 short的内容就是这么多。总的来说,short短整形的特性就是: 1.值范围是-~(整数) 2.类型字母为s 3.占用空间2字节 ok nbt标签的内容就暂且到这里了,我们下一章再见。 (补码是什么啊?) (简单来说,这八位的第一位是表示正负号,0为正,1为负。所以负值最小可以到-128即,正值最大可以到127即0。) (哦懂了懂了) (不光byte有补码,minecraft的十四种nbt数据类型中,除了字符串、复合标签、列表这三样,其他都有补码) (对了,byte作为布尔值时是没有补码的。实际上在java语言中,byte数值没有布尔值这个用途,表示布尔值的是一个叫boolean的数据类型,minecraft的nbt中mojang把boolean的功能合并到了byte中,所以这就是为什么byte还有一个挺突兀的布尔值功能) 第一百三十六章 真正深入了解nbt-2 在上一章的时候,我们知道了nbt一共有14种数据类型: [字符] 字符串(string) [数值] {整形} 字节型(byte:b) 短整型(short:s) 整型(int:i) 长整型(long:l) {浮点型(小数)} 单精度浮点型(float:f) 双精度浮点型(double:d) [数据] 复合标签(pound) 列表(list) [数组] 字节型数组(byte array:[b]) 整型数组(int array:[i]) 长整型数组(long array:[l]) 现在我们已经深入了解了字符串(string)、字节型(byte:b)和短整型(short:s)。在上一章的末尾,我提到了1.13版本及以后,mojang把附魔等级(lvl)的数据类型从short短整形改成了int整形。那么问题来了,什么是int整形呢? int整形是minecraft中很常见到(注意这里)的数据类型,根本原因就在于它无特定格式,也就是不需要填写类型字母,直接上数字就完事了。那么到底有多常见呢?如物品的耐久和损害值,类型就是int整形。红石比较器比较命令方块输出的模拟信号强度值类型,也是int整形(这就是为什么红石信号强度能超过15的原因)。其他的如效果持续时长、mc地图边长、红石比较器输出的信号强度等也是int整形。 没错,mc地图只要你电脑够好,在没有边界拦你的前提下,地图理论上最大可达到x=4.x10^18即(四百六十一京一千六百八十六兆零一百四十一亿三千二百四十二万零六百零九)个方块。 “mc牛逼!”(破音) 上面这几个例子都是mc原版的。在mod里,比如ic2的能量等级也是int整形。 估计你也发现了,上面说过mc地图边长是int整形,而mc地图的极限又是x,所以——int整形的上限是。 而我相信你在了解完字节型和短整形的值范围后,已经得出了一个数值范围的公式: -(n+1)~n(n为该值类型的上限,且n≠0)或 -(2??1)~2??1-1(n为该值类型的2进制位数) 把int整形值上限套进去,你就可以得到int整形的数值范围了: -21,4748,3648~21,4748,3647「-(231)~231-1」(4字节) 实际上int整形的内容也就只有这个数值范围,可以说是最简单的了。 总的来说,int整形的特性就是: 1.数值范围为-21,4748,3648~21,4748,3647「-(231)~231-1」(整数) 2.占用空间4字节 真的是灰常简单呢! 三个整形都完了,就剩下最后一个了: 长整型(long:l) long长整型,顾名思义,就是一串很长很长很长的整数,实际上也确实如此。它的类型字母为l(注意是大写),当然用“l”(l的小写,不是i的大写)也是可以的。 那么long长整形到底有多长呢?我们知道,最短的字节型占用1字节,然后是占用2字节的短整形,接着是4字节的整形,可以发现占用字节数是翻着倍上去的,所以我们的long长整形其占用空间达到了8字节!即64位。而64位的二进制最大值是: ,00000000,00000000,00000000,00000000,00000000,00000000,00000000 我们可以将其转化为10进制: 1x2?3+0x2?2+0x2?1+.......+0x21+0x2? =2?3+0+0+0+0+0+......+0+0 =2?3 既然8字节空间可存储的最大值为2?3,那么我们的long长整形其值范围就是: -(2?3)~2?3-1 或许这样子用次方表达表达不出来long长整形有多长,那么接下来,我们就要把这个次方化为一个正常的数字,坐稳了! 所以我们的long长整形其范围就是: -922,3372,0368,5477,5808~922,3372,0368,5477,5807 (负九百二十二京三千三百七十二兆零三百六十八亿五千四百七十七万五千八百零八至九百二十二京三千三百七十二兆零三百六十八亿五千四百七十七万五千八百零七) 真够长的,都是的平方()的两倍。 这下子懂了吧。现在我们举个例子。 举什么例子好呢?好像因为这家伙太长导致很少用到哎!这可咋办? 没错!实际上,long长整形在minecraft并不常用,你很难找到一个值为long长整形的标签。你与long长整形最近的一次接触,估计就只有世界的种子了吧(mc种子的值是long长整形,你填的字母或其他的特殊符号都会在世界生成时转化为数字)。 那么这样子吧。假设有这么一个标签:the_death_of_gu_zhenxing,作用就是存储着古振兴死的次数,其值为long长整形。假设古振兴已经死了8,388,608(223)次,那么其值就是: {the_death_of_gu_zhenxing:l} 懂了吧? 所以,long长整形的特性就是: 1.值范围是-922,3372,0368,5477,5808~922,3372,0368,5477,5807「-(2?3)~2?3-1」(整数) 2.占用空间8字节 3.类型字母为l和l(l的小写) 嗯,这就是整形的四个类型。由于作者时间的关系,这一章就到这了。下一章我们将会继续了解浮点数以及更多的东西。 第一百三十七章 真正深入了解nbt-3 在上一章,我们讲完了nbt数据类型中数值类型中的整形形式。按照作者我归纳的: [字符] 字符串(string) [数值] {整形} 字节型(byte:b) 短整型(short:s) 整型(int:i) 长整型(long:l) {浮点型(小数)} 单精度浮点型(float:f) 双精度浮点型(double:d) [数据] 复合标签(pound) 列表(list) [数组] 字节型数组(byte array:[b]) 整型数组(int array:[i]) 长整型数组(long array:[l]) 接下来就应该是小数(浮点数)了。 小数有两种数据类型,这两种类型我们都已经在之前的章节接触过,即: 单精度浮点型(float:f) 双精度浮点型(double:d) 在第一百三十二章,作者就讲过单精度浮点型和双精度浮点型的占用空间,即: 单精度浮点型——占用空间:32位(4字节) 双精度浮点型——占用空间:64位(8字节) 同时我也提了这两个类型的数值范围: 单精度浮点型:-3.4x103?~3.4x103? 双精度浮点型:-1.x103??~1.x103?? 经过了上一章的了解,我们已经知道同样是32位占用空间的long长整形,它的数值范围达到了: -(2?3)~2?3-1 即:-922''3372''0368''5477''5808~922''3372''0368''5477''5807 但单精度浮点型却达到了: -340''0000''0000''0000''0000''0000''0000''0000''0000''0000~340''0000''0000''0000''0000''0000''0000''0000''0000''0000(负三百四十涧至三百四十涧[注:一涧为万沟,一沟为万穰,一穰为万秭,一秭为万垓,一垓为万京]) 为什么在相同的存储空间下,long长整形的数值范围才达到京的程度,而float单精度浮点型的数值范围却已经达到了涧的程度了呢?这到底是人性的扭曲还是道德的沦丧? 这还没完。我们知道,整数它规定一个最大范围,正负整数就都有其自己的最大值和最小值了。但小数不一样,你规定一个最大值,但它还可以无限增加它的小数位数,如: 1.76x10???????????????? 这数虽然很小,但小到小数位数就有999''9999''9999''9999将近千兆位了。如果要表示这串数字,光是4b的空间是绝对不够的。所以,浮点数数值类型也有其自己的小数位数最大值: 单精度浮点型:45位小数位数 双精度浮点型:45位小数位数 看来小数位最大值都一样嘛。 刚才我们提了两个问题: 1.为什么在相同的空间下,long长整形的数值范围才达到京的程度,而float单精度浮点型的数值范围却已经达到了涧的程度了呢? 2.这到底是人性的扭曲还是道德的沦丧? 首先我们来解答第一个问题。 其实,不管是什么浮点数,管他是单精度、双精度还是三精度,它们都有一个标准,这个标准就是:ieee 754-2008(ieee二进位浮点数算术标准) 这个标准规定了很多东西,想深入了解的话可以去百度百科上,这里就不细讲了。 其中,最重要的也是最简单的莫过于一个公式: value=sign bitxexponent biasxfraction 即一个浮点数,等于符号位乘以指数偏移值再乘以分数值。 看不懂是吧?其实,浮点数的表示方法就是用到了我们在学前班就学到过的“科学计数法”。 比如我们的单精度浮点型,它的32个位分别是: 0''00000000''00000000000000000000000 (符号位:1)''(阶码:8)''(尾数:23) 看来还是看不懂啊。算了,总之,是因为浮点数采用了科学计数法的方式来存储,才可以在32位的空间内塞入这么大的数值。 这就是第一个问题的答案。 第二个问题的答案就非常简单了,是:无法确定,因为人类的情绪是无法用语言准确表达出来的,最多也只能表达个大概。 现在我们知道浮点数使用的是科学计数法来存储。这种存储方法有利也有弊:利在于可存储数值的范围扩大了很多;但弊也有,就是能准确存储的数值范围缩小了。 啥意思呢?刚才说过,long长整形的数值范围是: -922''3372''0368''5477''5808~922''3372''0368''5477''5807 在这个范围内,存储的数值都是非常准确的,不会你给了个在这个范围内的数,计算机就在后台为了方便给你这个数四舍五入或者砍了几个0。因此,我们就把这个long长整形的数值范围又叫做long长整形的有效数值范围。 但浮点数就不一样了,由于使用科学计数法存储,导致数值范围看起来很大,但实际有效数值范围只有那么一点点: 单精度浮点型:7位(整数) 双精度浮点型:16位(整数) 对比一下long长整形的有效数值范围:19位(整数) 哦天哪!这浮点数,就像是mc的真区块和假区块一样——别看mc边长可以达到21''4748''3647x21''4748''3647,实际上有效游玩范围只有2999''9999x2999''9999,出去了就各种bug、特性、崩坏,可能时不时还跳出个桌面。 这就告诉了我们一个人间真理: 很多时候,国产游戏广告的内容看起来很牛逼,实际上真实游戏内容只有宣传其中的1%都不到。 嗯,这很资本家。 好了,回到正题。我们目前已经知道了两个浮点型的数值范围、小数位数最大值、有效数值范围和占用存储空间。但别忘了,很多nbt数据类型都有类型字母的,我们的两个浮点型也不例外,都有自己的字母: 单精度浮点型:f 双精度浮点型:d 具体用法就不再多说了。 我们知道,浮点数是可以表示整数也可以表示小数的。那么在表示整数时,我们要不要加上小数点呢? 答案是加不加都可以,当然最好是加上。 总而言之,两个浮点型的特性分别是—— 单精度浮点型: 1.数值范围为-3.4x103?~3.4x103? 2.占用空间32位(4字节) 3.使用ieee 754-2008标准 4.小数位数最大值位45位 5.有效数值范围为7位整数 6.类型字母位f 7.小数部分都为0时(即值为整数),可不加小数点,但最好要加上。 双精度浮点型: 1.数值范围为-1.x103??~1.x103?? 2.占用空间64位(8字节) 3.使用ieee 754-2008标准 4.小数位数最大值位45位 5.有效数值范围为16位整数 6.类型字母位d 7.小数部分都为0时(即值为整数),可不加小数点,但最好要加上。 第一百三十八章 真正深入了解nbt-4 在前三章,我已经讲完了字符和数值类型的数据类型,现在我们再来看看下表: [字符] 字符串(string) [数值] {整形} 字节型(byte:b) 短整型(short:s) 整型(int:i) 长整型(long:l) {浮点型(小数)} 单精度浮点型(float:f) 双精度浮点型(double:d) [数据] 复合标签(pound) 列表(list) [数组] 字节型数组(byte array:[b]) 整型数组(int array:[i]) 长整型数组(long array:[l]) 按照顺序,接下来就应该到了[数据]这个数据类型了。而里面的这两个: 复合标签(pound) 列表(list) 都是我们已经非常熟悉的数据类型了,因为这两个数据类型特别常见。但神奇的是,它们也经常被忽略。 为何? 因为它们说到底,就是两种符号: {}——复合标签(pound) []——列表(list) 数据可以套娃在它们里面,而多个数据需要用英文半角逗号分割。 只不过,它们两的差别,是不是只有符号和名字的差别呢? 当然不是。 实际上,它们两绝对不是你想的那么简单。 首先,它们两的作用准确的来说是: 复合标签(pound):包含一段独立的nbt标签。如{killname:“mng“,killtime:6000} 列表(list):存储多个类型相同的数据。如{time:[2020,12,21]}。 看起来似乎也没什么不同的地方对吧? 我们知道,一个nbt最外层就是由{}来包裹着的,而里面存储着各个标签,每个标签用英文半角逗号分割。而复合标签也是这样子的,所以,复合标签的作用才这样说:包含一段独立的nbt标签。 如果你看不懂,那也没关系,我们可以通过名字理解。“复合标签”这个名字是由“复合”和“标签”。 “标签”这个词的意思相信大家都知道。那么“复合”又是什么意思呢? 答案很简单:指物体等因某种原因而结合起来 理解了“复合”的意思,再来看看“复合标签”,我们很快就可以理解这个词: 指多个标签结合起来 不得不说,汉语真是博大精深。那么接下来,我们再来看看列表。 上面已经说了,列表的作用就是:存储多个类型相同的数据。翻译这个为人话就是:把多个同样类型的东西统一存储起来。 这就说明了什么?这就说明了列表的“[]”包含的只能是指定类型的数据,实际上还属于值的范围。而{}包含的就不是指定类型的数据了,而是标签!这就是两种数据类型的不同之处。 所以在列表中才不用写数据类型,因为大家都一样。这就像是乘法分配律,把公因数都提取出来,进行简化算式。 现在搞懂这两个的区别了吧?我相信你已经搞懂了。 如果你还不懂,看看上面的两个例子。 好了,相信各位都已经准备好了,那么接下来我们就进入下一阶段。 我们知道,列表可以存储多个类型相同的数据。那么当数据是复合标签时,该怎么办? 很简单,其实这种情况我们已经遇见过很多次了,比如我们最了解的enchantments(\/?n?t??ntm?nts\/)标签,我们都知道它的格式是这样的: {enchantments:[{id:<魔咒id:string字符串>,lvl:<级数:int整形>}]} 可以发现,这里就出现了[{}]这种组合。如果你细心观察,你就会发现:列表里每项复合标签里的标签名称、格式都是完全一样的。 这说明了什么?这就说明了如果列表的项是复合标签,那么每个复合标签里的格式、标签名称都是完全一样的。 这很简单对吧? 实际上到此为止,关于复合标签和列表这两项数据类型就已经讲完了。 ........ 但此时,仍然有一个未解之谜: 我们知道,列表的项可以有很多。那么列表的项数到底有没有上限呢? 答案很简单:在没有明确规定列表的格式时,列表的项数理论上是无上限的。(明确规定列表格式的,比如在第一百三十二章讲到的armordropchances) 只不过在实际操作过程中,列表还是有上限的:硬件。 嗯.......这可真是对了那句话:硬件决定上限,软件决定下限。 ok那么这一章就到这里了,我们下一章再见。 第一百三十九章 真正深入了解nbt-5 好消息!我们已经只剩下“数组”这个数据类型了! [字符] 字符串(string) [数值] {整形} 字节型(byte:b) 短整型(short:s) 整型(int:i) 长整型(long:l) {浮点型(小数)} 单精度浮点型(float:f) 双精度浮点型(double:d) [数据] 复合标签(pound) 列表(list) [数组] 字节型数组(byte array:[b]) 整型数组(int array:[i]) 长整型数组(long array:[l]) 看上面的列表,我们就可以知道,数组类型一共有三个: 字节型数组(byte array:[b]) 整型数组(int array:[i]) 长整型数组(long array:[l]) 当然,在了解之前,我们得先来了解一下“数组”是什么意思。 其实很容易理解:数组,就是指几个数字组合在一起。 这就简单了,加上这三个名字前分别带有“字节型、“整型”、“长整型”,我们就知道了这三个数组到底是个什么鬼东西: 字节型数组:几个字节型值组合在一起。 整型数组:几个整型值组合在一起。 长整型数组:几个长整型值组合在一起。 三个数组的基本就是这样。这时候,我们就可以进入下一阶段了: 它们三到底长啥样? 我们知道,列表数据类型的作用就是将几个数据类型相同的数据集合在一起,如: {time:[2020,12,21]} 而数组,刚才上面讲过了:几个数字组合在一起。 我们可以把几个数字看成“几个数据类型相同的数值”,那么就变成了: 将几个数据类型相同的数值集合在一起 对比一下,你就会发现:数组不就是数据类型为字节型、整型或长整型的列表嘛! 所以我们就可以大胆猜测,数组是长这样子的: [<数值1>,<数值2>,<数值3>.......](如:[2020,12,21]) 猜的可以,但并不是全部的真相。 我们在讲数值数据类型时,经常提到四个字:类型字母。而现在我们讲到了集数值和列表为一体的数组,那是不是也有类型字母呢? 答案是肯定的。所以实际上的数组格式,是这样子的: [<类型字母>;<数值1>,<数值2>,<数值3>.......] 举个例子,比如数据类型为字节型的数组: [b;11,45,14] 不难发现,决定类型字母的就是该数组的数据类型。只不过之前我并没有提到整形的类型字母,但相信大家不难猜出来,因为: 整型(int:i) 所以整形的类型字母就是:i。 按理说这一章到这里也就完了,但如果有细心的人,或许会提出一个疑问: 那么后面的数值需要填上类型字母吗? 答案很简单:不用。 理由也很简单:分配律。 现在我们来举些例子: 一、{time:[i;2020,12,27]}(数据类型为整形) 二、{covid-19:{america:[l;,,,]},time:[i;2020,12,27,21,44,54]}(第一个数据类型为长整型,第二个数据类型为整形) 三、{options:[b;1,1,0,0,1,1,1,1,1,0,0,1,0,1]}(数据类型为字节型) ok本章就到这里了。 ...... ...... ...... 哦对了,请记住一点:数组里的类型字母后面那个符号是分号(;)而不是冒号(:)! 第一百四十章 真正深入了解nbt-6 (真正深入了解nbt-6) (注意,本章中指出的中文minecraft wiki错误现已修正) 在前五章,我们仔细地了解了一下nbt的数据类型。现在,我们已经了解得差不多了,那么还剩下什么呢? nbt的版本 ——第三节:nbt的版本 nbt最早在indev版本就出现了,但是当时只有0到10这11个标签可用。 后来,到了minecraft beta1.3,nbt正式有了第一个格式版本: minecraft 1.2版本时,notch引入了anvil[.mca]文件格式来存储区块,在此之前存储区块的文件格式为region[.mcr](minecraft beta1.3时为存储区块引入的)。而随着anvil的引入,nbt的版本正式由升级到了,虽然只是新加入了一个整形数组(int array:[i])。 神奇的是,1.12版本时加入long长整型时并没有更新nbt格式版本号。 nbt的版本就是这样,但它对我们有啥影响呢? 目前,如果我们要编辑nbt文件,我们除了使用java版1.13及之后minecraft内置的snbt和压缩后(gzip压缩)的nbt文件的转换器来编辑nbt文件,还可以使用第三方软件编辑nbt的文件。如果我们使用第三方软件nbt编辑文件的话,nbt的格式版本此时就有些影响了: nbtedit————windows nbtexplorer————windows\/mac\/liunx neinedit————mac mineback ultimate————windows nbt2yaml————windows webnbt————浏览器 nbt grammar for synalyze it————mac 如上,每个软件所支持的nbt格式是不同的。只不过,对我们的影响似乎也就这一点。 ——第四节:snbt 上面我有提到一个东西:snbt,那么snbt是个什么鬼东西呢? 其实它并不是一个鬼,而且它并不陌生,我们已经见过它很多很多次了。 它的全称就是:string named binary tags(字符串化的二进制命名标签) 似乎这么说来还有点陌生。那么就直白点说吧,snbt就是纯文本形式的nbt,且通常用于指令!我们所见到的所有文本形式的nbt都是snbt! ——第五节:nbt?snbt 我们现在知道了nbt文件它其实是二进制的,且不同于我们平常所见到的snbt。那么,我们该怎样转化nbt和snbt呢? 其实很简单,上面提到mc社区里有许多第三方软件,随便下一个基本上就可以了。 但第三方软件毕竟不是mojang开发的。那么mojang这个官方有开发吗? 答案是肯定的。 java版1.13之后,mc服务端就有自带的数据生成器。这个数据生成器有这么几个功能: 1实现nbt(.nbt)?snbt(.snbt) 2生成原版数据包的全部内容 3生成一个列出了所有方块状态、注册名和完整的原版命令树的json文件 那么我们该如何启动它呢? 很不简单。首先,我们需要一个minecraft 1.13版本及以上的服务端,你可以在mcbbs或者是官方启动器上下载,只不过官方的下载.......你需要一个迅雷。 下载完后,你可以直接粗暴地双击server.jar(服务端),你也可以按照作品相关里的教程自己创建一个.bat文件方便打开: @echo off color 0 title a minecraft server java -xms2g -xmx2g -jar server.jar pause 如果你打开不了,那有3种可能: 1.你抄错了上面的指令(方法:细心检查) 2.你未安装java(方法:安装一个java 8) 3.你安了个32位的java(方法:卸了,重新装一个64位的java 8,或把-xms2g -xmx2g调成-xms1g -xmx1g) (会不会有人打开不了,发现没安java,于是下了个32位的java 10,只不过不是脱机的,然后嫌下载慢随便在网上找了一个。结果java安好了,捆绑软件也一大堆,浏览器主页还被改了。再次打开仍然打开不了,于是删了java 10,去下了个64位的java 10,这次聪明用脱机。结果发现系统是32位,不知道怎么弄,弄来弄去还差点把windows换成了mac。最后重新买了一台装了64位的windows系统电脑,花了998$。安了64bit java 10,再次打开,发现还是打开不了。然后才了解到mc是java8的,于是下了java 8 64bit脱机,结果仍然打不开。最后终于发现原来打成了: @echo off color 0 title a minecraft server java -xms2g -xmx2g -jar server pause) 回到正题。 按照作品相关里的教程,我们配置好服务器后(实际上不用配置也可以),这样子做: 首先,打开命令提示符(windows)或终端(mac) 打开方法这里就不多叙述了。 然后复制这一串代码: java -cp server.jar.minecraft.data.main 复制粘贴进去不要立刻执行,因为这毛用都没有,还会显示: (windows) 错误:找不到或无法加载主类.minecraft.data.main (mac) 错误:找不到或无法加载主类.minecraft.data.main 原因: javang.ssnotfoundexception:.minecraft.data.main 那么该怎么办呢? 其实很简单,你直接输入进去这系统压根就找不到server.jar这个文件,所以,这里你就要这样子: 打开你的server.jar所在的文件位置,然后直接把整个server.jar文件拖进去,你就会发现系统自动给你输入了server.jar的路径。 现在好了,你只需要用这段路径替换原来的server.jar,比如你的server.jar路径是: d:\\minecraft\\minecraft server\\1.13.2\\我的世界1.13.2官方服务端.jar(windows) \/users\/block\/desktop\/桌面文件\/server\/server.jar(mac) 那么你替换之后,就会变成这个样子: java -cp d:\\minecraft\\minecraft server\\1.13.2\\我的世界1.13.2官方服务端.jar.minecraft.data.main(windows) java -cp \/users\/block\/desktop\/桌面文件\/server\/server.jar.minecraft.data.main(mac) 现在,执行,你就成功——走出了第一步。系统找到了这个server.jar,并执行了指令,只要你这个server.jar是1.13版本及以上的,那么就会跳出: option description ----------------- --all include all generators --client include client generators --dev include development tools --help show the help menu --inputstring input folder --outputstring output folder (default: generated) --reports include data reports --server include server generators 这是啥意思呢?我们把这一大串放到生草机里去搅拌一下,就会得到: 选项说明 ----------------- --全部 包括所有发电机 --客户 包括客户端生成器 --开发 包括开发工具 --救命 显示帮助菜单 --输入 输入文件夹 --输出 输出文件夹(默认:生成) --报告 包括数据报告 --服务器 包括服务器生成器 差不多可以看出一些端倪,只不过这仍然太生草了。所以我们需要上一下minecraft wiki,得出这些东西的具体用途是: --all 生成原版数据包 --client 生成assets\/minecraft文件夹,包含blockstates和models文件夹 --dev 用于nbt文件和snbt文件的相互转换[需要验证] --help 显示选项和描述列表 --input 输入含有nbt或snbt文件的文件夹 --output 规定输出的目标文件夹,若目标文件夹不存在则自动新建该文件夹(默认为generated) --reports 生成reports文件夹,包含biomes文件夹和blocks、mands、registries三个json文件 --server 生成data\/minecraft文件夹,包含advancements、loot_tables、recipes、tags四个文件夹 --validate [需要更多信息] 现在我们可以尝试生成一个原版的数据包,这就需要在控制台上输入: java -cp d:\\minecraft\\minecraft server\\1.13.2\\我的世界1.13.2官方服务端.jar.minecraft.data.main --all(没错,只需要在原本的后面加上你要执行的指令就可以了),回车运行。 然后你就会发现出现了一大串的信息。 接着,到目录去查看...... 反正作者这边什么东西也没有生成。minecraft wiki上还写着: 原版数据包(pack.mcmeta文件除外)将生成在当前文件夹的generated目录中。 难不成是打开方式不对? 来试试其他的功能吧,比如这个--help,看一下会有什么帮助: java -cp d:\\minecraft\\minecraft server\\1.13.2\\我的世界1.13.2官方服务端.jar.minecraft.data.main --help 结果......还是这个界面: option description ----------------- --all include all generators --client include client generators --dev include development tools --help show the help menu --input input folder --output output folder (default: generated) --reports include data reports --server include server generators 就很离谱。 对了,我们最开始不是要转换文件的吗?咋弄成这个了? 好,那现在我们就开始尝试一下--dev: java -cp d:\\minecraft\\minecraft server\\1.13.2\\我的世界1.13.2官方服务端.jar.minecraft.data.main --dev --input“d:\\minecraft\\minecraft server\\1.13.2\\world“ 然后...... 实际上这是一个错误的做法。正确的做法应该这样子: 在服务端这个目录创建一个新的文件夹(实际上也不用创建,创建只是为了更好的把要转换的文件集中起来),并将其取名为:input 然后,找到实际上是以nbt存储的.dat的文件(比如world下的level.dat),将它们丢进去。 接下来,改这些文件的后缀.dat为.nbt。 最后,最重要的一点,执行: java -cp d:\\minecraft\\minecraft server\\1.13.2\\我的世界1.13.2官方服务端.jar.minecraft.data.main --dev --input “d:\\minecraft\\minecraft server\\1.13.2\\input“ (注意,空格一定要空,作者最开始时就是少了一个空格,然后就是一堆问题!特别是--input和后面的文件夹路径中间一定要空!这是个坑!) 然后,当出现: [xx:xx:xx][main\/info]: starting provider: nbt to snbt [xx:xx:xx][main\/info]: converted level from nbt to snbt [xx:xx:xx][main\/info]: nbt to snbt finished after xxx ms 恭喜你!你成功了! 但转换后的文件去哪了呢? 答案很简单: c:\\users\\xxxxx\\generated(windows) \/users\/xxxxxx\/generated(mac) 找到这个目录,你就会发现了自己期待已久的: .snbt! 这个文件你现在可以用记事本来打开并修改了。 但现在问题又来了,我们现在可以使用dev来进行.nbt→.snbt,那该怎么.nbt←.snbt呢? 很简单。我们把刚才弄出来的.snbt文件再放进input文件夹,顺便删掉那个.nbt。再度执行: java -cp d:\\minecraft\\minecraft server\\1.13.2\\我的世界1.13.2官方服务端.jar.minecraft.data.main --dev --input “d:\\minecraft\\minecraft server\\1.13.2\\input“ 然后你就会发现这不行。 为啥呢?minecraft wiki上说: 用于nbt文件和snbt文件的相互转换[需要验证] 很明显这里错了,--dev只能是.nbt→.snbt,并不能.nbt←.snbt。 那该怎么办呢? 使用--client: java -cp d:\\minecraft\\minecraft server\\1.13.2\\我的世界1.13.2官方服务端.jar.minecraft.data.main --client --input “d:\\minecraft\\minecraft server\\1.13.2\\input“ 然后: [xx:xx:xx][main\/info]: starting provider: snbt - nbt [xx:xx:xx][main\/info]: snbt - nbt finished after xxx ms minecraft wiki上这样介绍--client: 生成assets\/minecraft文件夹,包含blockstates和models文件夹 很明显这句话完全错误(来自2021-8-5的注:实际上并不是完全错误,确实有这功能,只不过还附带了.nbt←.snbt的功能)。实际上,--client的作用就是.nbt←.snbt。现在你打开generated,你就会发现.snbt重新被转换成了.nbt。 现在我们知道了--dev是.nbt→.snbt,--client是.nbt←.snbt,也发现了minecraft wiki中的错误。剩下的内容,我们就以后再研究了,毕竟剩下的不是本章的重点。 ok那么nbt就讲到这了。我们下一章再见。 第一百四十一章 牛顿心中的minecraft:下落的方块 前十二章,我们详细地了解了生物的共通nbt以及nbt格式。但别忘了,本卷的名字叫做: 实体与nbt 所以接下来,我们就要回归正题。 ——第一节:关于下落的方块这个大类只有一种实体这档事 在第一百二十九章里,我们知道了很多关于实体的东东。比如:下落的方块是个实体。 但有没有人想过这么一个问题: 我在对下落的方块这种实体举例子的时候,为什么举了一个“下落的方块”实体的例子? 深入思考的话,我们就会得出一个神奇的结论:下落的方块这种实体只有一个实体——下落的方块(fallingsand[1.13之前]、falling_block[1.13及之后]) 所以这就可以解释你在用kill清除实体时,就不会跳出来“下落的沙子”了,更不会跳出来“沙子”(因为这名字已经被掉落物占了),而是统一“下落的方块”。因为人家变成实体之后就统一成了一个实体。 再深入思考,我们又会得到一个问题: 统一成一个实体后,下落的方块是如何确定自身到底是什么方块的? 为了解决这个问题,我们可以回顾一下第一百零八章到第一百零九章对掉落物的介绍,就会得出一个对掉落物确定自己到底是什么物品的方法的结论: 用nbt存储物品的信息 按理来说,用实验法来研究生物,得出结论后也就差不多了。但我们不是在进行一个生物实验,而是在学习nbt。况且,就算我们这是一本生物书,生物学它本身也是一个: ...→观察并思考→提出问题→收集资料→作出假设→制定实验计划→实施实验并记录→得出结果→研究并思考→提出新的问题→... 所以我们可以研究这个结论,并提出一个新的问题: 为什么掉落物要用nbt来存储物品的信息呢,而不用item_<物品id>这样子每个物品的掉落物都有一个对应的单独实体? 答案很简单: 1mojang这个喜欢3的家伙很懒(主要原因) 2如果这样子做的话虽然也能达到目的,但游戏会更大 深入思考,我们还会得出一个震惊的结论: 这样子的话,那么掉落物这个大类也只有一个实体唉:掉落物 实际上还真是这样的,掉落物确实只有一个实体:minecraft:item (注意!minecraft:item_frame这个实体实际上是物品展示框,而不是掉落物) 得出了这些结论,我们再来看看下落的方块。刚才我们发现下落的方块只有一个实体:下落的方块。这说明了什么? 下落的方块也是使用nbt来存储方块的信息。 这就是上面那个问题的答案。 ——第二节:下落的方块的nbt 下落的方块中存储着方块信息的nbt是: blockstate(复合标签) 意思是:block(方块)state(状态) 这个复合标签里有两个重要的东西: name(字符串):这个正在下落的方块的id properties(复合标签):可选,这个正在下落的方块的方块状态 举个例子。比如,现在这里有一个沙子被炸飞了,那么它的blockstate很有可能是: {blockstate:{name:“minecraft:sand“}} properties这个先不管,方块状态等我们以后讲到你就立马会了。 我们可以使用\/summon minecraft:falling_block(1.11及之后,之前为\/summon minecraft:fallingsand)来生成一个下落的方块。按照生成掉落物的经验,我们就可以搞出一些神奇的东西,比如: \/summon minecraft:falling_block ~~~{blockstate:{name:“minecraft:diamond_block“}} 执行它,你的下半身就会立马被一个钻石块包裹。然后这个钻石块开始下落,接着就消失了! 如果你用循环命令方块来执行,建议你稍微改一下指令: \/summon minecraft:falling_block ~~2 ~{blockstate:{name:“minecraft:diamond_block“}} 开启!你就会发现你搞出来了一个不断在空中振动(???)的没有碰撞箱(???)的钻石块(???)。 这到底是怎么一回事呢? 实际上还有更有趣的。 如果你在这个不断振动的钻石块的位置上放置一个钻石块。如果下面是空的,你就会发现: 你放置的这个钻石块给这个在不断振动的钻石块给震掉下来了! 还可以更奇葩吗? 可以! 如果下面有方块,你还放的话,你就会发现: 你放置的这个钻石块给这个在不断振动的钻石块给感染了!成了钻石块下落,每到地面就重新下落,直到下面被打掉!(建议可以的亲自去做一下这个实验) 为什么会成这个样子呢? 因为time没填,默认为0。 time(int整形):该下落的方块已存在的刻数,不设置默认为0。如为0,则: 当time从0变为1时,如该实体的位置上的方块与其存储的方块一致,则继续下落,并删除该方块。不一致,则删除该实体。(这应该就是方块开始下落时游戏的替换原理) 如不为0,当time值大于600(30秒)或time值大于100(5秒)时超出建筑限制(y大于255或小于0),就变为掉落物。 所以,为了让这个钻石块能够快快乐乐地下落,我们就需要: \/summon minecraft:falling_block ~~~{blockstate:{name:“minecraft:diamond_block“},time:1} 然后你就会发现: 钻石块竟然不浮空了,而是成功掉了下来! (the strangeughter in newton''s coffin frightened the tourists around him. ——british broadcast corporation report) blockstate和time这两个标签是必填项。除此之外,还有一些非必填项: tileentitydata(复合标签):该实体存储的方块的方块实体标签 dropitem(byte字节型:1或0[true|false]):该实体被破坏后是否掉落其方块的物品形式。为1时掉落,但如果其方块没有对应的物品则仍然不会有物品掉落。 hurtentities(byte字节型:1或0[true|false]):该实体掉落时碰到其他实体是否对其造成伤害。为1时造成。 fallhurtmax(int整形):被砸中的实体所承受的伤害上限。一般的方块默认为40滴血(20?) fallhurtamount(float单精度浮点型):给被砸中的实体造成的伤害=falldistance(当前实体已经坠落的距离)xfallhurtamount(该标签)。一般的方块默认为2。 举个例子,比如你召唤一个下落的水方块(???): \/summon minecraft:falling_block ~~~{blockstate:{name:“minecraft:water“},time:1,dropitem:0,hurtentities:1,fallhurtmax:150,fallhurtamount:1.1} 召唤后,你会发现你看不到下落的水方块。唯一能体现它存在的只有在它落地变为方块之后。 而如果你从25米高空扔下一个这样的下落水方块,假设下面有一个正在整理物品的有20滴血的玩家。几秒后,他就会原地去世,同时原地会凭空出现一摊水(忽然发现这可以做一些有趣的东西,因为这就像一个活生生的人其体内除了水其他物质都突然凭空消失的样子)。 而他受到了多少伤害呢? 根据“给被砸中的实体造成的伤害=falldistancexfallhurtamount”这个公式,我们可以轻易得出: 给被砸中的实体造成的伤害=25x1.1=27.5(13.25?) 怪不得这名玩家会原地去世。 (tileentitydata这个标签等我以后讲方块时候再来了解) ——第三节:下落的方块的神奇用途 下落的方块有许多有趣的用途。 在第一百一十二章到第一百一十三章,我们了解了实体的通用标签。在此之中,有这么几个标签和下落的方块配合时会表现得很好: nogravity(byte字节型):控制实体是否掉落 motion(列表):记录实体在dx、dy、dz三个轴的速度 上面我们搞出来一个神奇的不断在空中振动的没有碰撞箱的钻石块。那我们可以弄出一个静止在空中的可以穿过去的钻石块吗? 可以! nogravity是控制实体是否掉落的,当为1时实体不会坠落。所以我们可以: \/summon minecraft:falling_block ~~~{blockstate:{name:“minecraft:diamond_block“},time:1,nogravity:1} 然后...... 妈妈你快看!这个钻石块它浮在空中唉!看,我可以走过去!也可以回来!现在我头在钻石块里面! (newton''s coffin lid suddenly shook, frightening passers-by. ——british broadcast corporation report) 只不过这有一个坏处,就是当time过600它就会变成掉落物。 所以我们可以这样子: 重复执行\/summon minecraft:falling_block ~~5 ~{blockstate:{name:“minecraft:diamond_block“},time:1,nogravity:1,dropitem:0,customname:“{\\“name\\“:\\“diamond_block\\“}“}→连锁有条件的保持开启\/kill @e[type=falling_block,name=“diamond_block“] 这样子,我们就可以一直保持这个幽灵钻石块存在。 知道了如何坑朋友之后,我们还可以玩点新花样: motion这个标签可以让我们设置实体的运动。通过它+mc的物理运动,我们就可以弄出一些新的东西,比如一个最基础的: \/summon minecraft:falling_block ~~~{blockstate:{name:“minecraft:redstone_block“},time:1,dropitem:0,motion:[0.7d,0.5d,0.3d]} (对了,当时对motion是一笔带过,这里讲一下。motion的值是列表,列表里有三个值: [dx速度,dy速度,dz速度],值类型都是双精度浮点型(double:d),单位是米\/刻。) 然后你就会发现飞出了一个红石。 好像也没什么稀奇的。但别忘了,一些全身由人类五脏中以代谢功能为主的一个器官构成的人会玩出一些新花样,比如制作一个神奇的方块动画。 如果你不是这样的人,那么你可以干些其他的实验,比如一直重复执行这条指令,命令方块会帮你造出一个很神奇的建筑。 你也可以乱改数据,这新花样是有很大的发挥空间的。 ——第四节:结束 现在我们来总结一下: [必]blockstate(复合标签) ——[必]name(字符串):这个正在下落的方块的id ——properties(复合标签):可选,这个正在下落的方块的方块状态 [必]time(int整形):该下落的方块已存在的刻数,不设置默认为0。如为0,则当time从0变为1时,如该实体的位置上的方块与其存储的方块id一致,则继续下落,并删除该方块。不一致,则删除该实体。如不为0,当time值大于600(30秒)或time值大于100(5秒)时超出建筑限制(y>255或<0),就变为掉落物。 tileentitydata(复合标签):该实体存储的方块的方块实体标签 dropitem(byte字节型:1或0[true|false]):该实体被破坏后是否掉落其方块的物品形式。为1时掉落,但如果其方块没有对应的物品则仍然不会有物品掉落。 hurtentities(byte字节型:1或0[true|false]):该实体掉落时碰到其他实体是否对其造成伤害。为1时造成。 fallhurtmax(int整形):被砸中的实体所承受的伤害上限。一般的方块默认为40滴血 fallhurtamount(float单精度浮点型):给被砸中的实体造成的伤害=falldistance(当前实体已经坠落的距离)xfallhurtamount(该标签)。一般的方块默认为2。 ok本章就到这里了,我们下一章再见。 ===========资料============ ——下落的方块历史 java版infdev ——加入了应用于沙子和沙砾的id fallingsand。 java版 1.0.0——beta 1.9 prerelease 6——加入了可以下落的方块龙蛋。 1.4.2——12w41a——加入了可以下落的方块铁砧。 1.7.2——13w39a——加入了可以下落的方块红沙。 1.12——17w06a——加入了可以下落的方块混凝土粉末。 1.13——17w47a——重命名 fallingsand 到 falling_block。 1.14——18w45a——加入了可以下落的方块脚手架。 携带版alpha 0.6.0——沙子和沙砾现在可以下落了。 0.9.0——build 1——加入了可以下落的方块红沙。 0.12.1——build 1——加入了可以下落的方块铁砧。 携带版 1.0.0——alpha 0.17.0.1——加入了可以下落的方块龙蛋。 1.1.0——alpha 1.1.0.0——加入了可以下落的方块混凝土粉末。 基岩版 1.8.0——beta 1.8.0.8——加入了可以下落的方块脚手架。 原主机版 tu1——————1.00———————————加入了可以下落的方块沙子和沙砾。 tu9——cu1——————patch 1——————加入了可以下落的方块龙蛋。 tu14——————1.05———————1.0.1——加入了可以下落的方块铁砧。 tu31——cu19——1.22—patch 3——————加入了可以下落的方块红沙。 tu53——cu43——1.49—patch 23——1.0.3——加入了可以下落的方块混凝土粉末。 —————————1.83——————————加入了可以下落的方块脚手架。 new nintendo 3ds版 0.1.0——加入了可以下落的方块沙子、沙砾、红沙和铁砧。 1.7.10——加入了可以下落的方块龙蛋。 1.9.19——加入了可以下落的方块混凝土粉末。 ++++++++++++++++ 王五正在翻看minecraft wiki中文,去学习下落的方块的使用方式。张三在旁边修理刷物机。 张三叮叮当当地把刷物机搞了一阵子后,发现得出去到主城东方的那座山里的黑市买些材料。由于他们几个的工作,导致他们的基地是在离主城很远的一座山下面。如果马不停蹄,最快也要三天才能到那里。于是他就收拾了工具,打算把这事情先放一放。 张三收拾着工具,突然发现门被打开了,走进来一个人。张三想把这人哄出去,想了一下最后站起来问:“你是谁?你从哪儿来?到这要干什么?” 他回答:“我叫刘一,从主城丁龙区来,来这是王五邀请我的。”刘一说着,眼角的余光发现王五愁眉苦脸。他很好奇,正好王五也注意到刘一来了,便招呼刘一过来。张三见是王五请来的,便不再说什么。 刘一第一句话就是:“王五啊,发生甚么事了?” 王五打开了几张游戏截图给刘一看。刘一一看,原来是刚才,有两个下落的方块,在三十多米高的高空,一个质量九百多公斤,一个质量八百多公斤。王五说,有一个是他一直重复执行弄出来的沙子,就是很奇怪一生成就消失,而且他都写了是diamond_block,大佬你能不能教教我这是怎么一回事,帮助修复一下我的下落的方块。刘一说:“可以。你在游戏里弄来弄去,不好,得灵活变通,去看看minecraft wiki中文。”王五反驳:“刚刚我就在看唉,这就是我按照上面弄出来的!”刘一思考了一下,回:“你把指令给我看一下,应该是time值的问题。” 王五打开了命令方块,只见上面写着: \/summon minecraft:falling_block {blockstate:{name:“minecraft:diamond_block“},time:1} 刘一仔细观察,发现了一个问题:“你这没有坐标啊,应该是\/summon minecraft:falling_block ~~~{blockstate:{name:“minecraft:diamond_block“},time:1}。” “哦,原来如此。”王五这才想起来\/summon的格式是\/summon <实体id>[坐标:xyz][nbt]。 试了试,可以正常下落,但还是沙子。 “下落的问题是解决了,但这仍然是沙子啊,不是钻石块。这该怎么办?”王五看着刘一,眼睛睁的贼大。刘一看着这个好奇宝宝,发现越看越可爱,于是摸了一下王五的头,说:“这应该是你标签名没写对或是id没对。” 王五仔细检查了一下,blockstate正确,name正确,minecraft:diamond_block也正确。 刘一这才发现事情不简单,皱起了眉头仔细思考。他突然看到游戏界面左上角的minecraft 1.12.2,灵光一闪,拍手叫道:“是不是版本的问题?!” 王五一听,赶紧打开minecraft wiki中文,点开history,发现了一个问题:下落的方块中文百科最早也已经是2020年4月13日09:31。王五试图在英文百科上找,发现页面虽早,但数据值那个页面早已不见。 这下子该如何是好?在发现minecraft wiki其早期记载的资料已经无法参考了之后,两人就像是热锅上的蚂蚁,因为对于这种事情两人还是第一次遇到。 张三已经整理完了工具,正无事可干打算拿起手机看一下敦煌防护林已经反转多少次时,突然发现旁边还有两个蹦来蹦去的蚂蚁,于是拿起了一个西瓜,问两人发生了什么事。 在了解了具体情况后,张三感到震惊——minecraft wiki对于早期的资料保护竟然这么懈怠,万一以后minecraft30周年,新玩家想要回顾的时候,如果minecraft wiki还这样,那么他们或许就只知道minecraft有猪灵和僵尸猪灵,却不知道在很久以前只有僵尸猪人。这还是比较重要的资料,如果像是更生僻的比如nbt,或许情况会更糟。 “互联网还真是没有记忆啊。”张三感叹道。感叹虽感叹,张三还是仔细想了一下。这一想,他突然想到一点:“扁平化!” 刘一愣了一下,然后赶紧打开扁平化的页面。果真,还真有这么一句: 下落的方块的block数据和data数据合并成了blockstate。 但这里并没有讲到“block”和“data”到底是个什么鬼。 进展很快就停止了。三人继续想,但再也没有了新点子。 最怕空气突然安静。 王五再一次打开下落的方块页面。他突然发现还有一个: 教程\/下落的方块 点开历史,他很快从悲哀转为震惊,接着又转为惊喜,最后情绪化成了声音:“哦吼。哦吼!哦吼!!!” 三人迅速浏览了历史,得出了一些重要的结论: 1java1.13扁平化之前,blockstate是分为两个标签:data和block 2block是字符串,在里面写入方块英文id就可以指定该下落的方块代表的方块 3data在教程\/下落的方块里并未提及,但应该是和properties一样,值为复合标签,代表该方块的方块状态。 4在更早的版本(1.8以前),没有block标签,而是使用tileid标签。tileid应该是int整形,在值里填上方块数字id就可以指定该下落的方块所代表的方块。这就可以解释为什么现在的wiki在介绍time标签时有这么一句话:“time刻数在从0变为1的这段时间里,如果在它的位置上方块的 id 和实体 tileid 都相同,那么这个方块就不会被删除......” 最终,王五得出了一个正确的指令: \/summon minecraft:falling_block ~~~{block:“minecraft:diamond_block“,time:1} 使用该指令,王五成功在1.12.2版本召唤出一个下落的钻石块! 第189章 我们知道,在minecraft中,共通标签有这么几个: 实体共通标签 生物共同标签 物品共通标签 方块实体共通标签 但你们可能不知道,还有这么一个神奇的共通标签: 矿车共通标签 没错,矿车也有共同标签。可能是因为矿车的种类比较多吧。 ——第一节:什么是矿车共通标签? 矿车共通标签,相信懂中文的都看得懂,就是矿车们的nbt中互通的标签。只不过“矿车共通标签”相对来说比较冷门,除了矿车本身比较冷门,还有一点是因为: 矿车共通标签内的标签都是非必填项! 这就导致了一点,就是该共通标签就算知道了也很少用到(毕竟谁会去研究一个没有盖子的铁盒子呢?)。 但有时候也是会用到的。 现在,就让我们康康这些标签到底是个什么东西。 ——第二节:矿车共通标签的内容 内容准确的来说,只有三项: customdisytile(byte字节型:1 or 0[true|false]):选择是否展示矿车里我们搞出来的方块。1为展示。0为不展示。 disystate(复合):设置放在矿车里的方块。 disyoffset(int整形):设置放在矿车里的方块其位置会偏移多少像素。为正数+时向上偏移,为负数-时向下偏移。由于mc中1方块边长都是16像素(一米),所以当值为16的倍数时会让方块正好移动一米。 customdisytile这就不用说了,因为上面已经讲得很清楚了。我们只需要举个例子: 假设这个矿车是一个tnt矿车。如果要该矿车里的tnt消失,就要设置该tnt矿车中的 {customdisytile:1}→{customdisytile:0} +++++++++ disystate是一个复合标签,我们已经知道这是用于设置矿车里的方块的。 那该如何设置呢? 很简单,让我们康康其内容: name(字符串):该方块的方块id properties(复合):非必填。该方块的方块状态。 嗯......这基本上和我们下落的方块是一样的。 properties不用说,以后再来研究。 name就更不用说,直接举个例子: \/summon minecraft:minecart ~~~{customdisytile:1,disystate:{name:“minecraft:diamond_block“}} 这样子,你就会获得一个里面放着钻石块的矿车!而且你还可以坐上去! (只不过打掉好像并不会获得钻石块) +++++++++ 现在,我们只剩下了一个:disyoffset disyoffset仍然很简单。直接上例子: \/summon minecraft:minecart ~~~{customdisytile:1,disystate:{name:“minecraft:diamond_block“},disyoffset:32} 执行它,你将会获得一个上面飘着钻石块的矿车! 如果你坐上去,这个钻石块也会刚好顶在你的头上。 (把32改为-32会怎么样?) ——第三节:旧版本 如果你看过修改后的上一章,那你应该就看过在此章末尾的小剧场。在此小剧场中,王五、张三、刘一三人四处查找,最终找到了1.12.2版本下落的方块的正确使用方式。 在上面,我们发现disystate其内容和下落的方块blockstate标签基本相同。而下落的方块blockstate经过他们三人的探索后,发现其是在1.13扁平化时由block和data组成。 那么,既然disystate和blockstate这么像,那么...... 在1.12.2版本使用\/summon minecraft:minecart ~~~{customdisytile:1,disystate:{name:“minecraft:diamond_block“}}会发生什么? 答案很简单,生成一个空空如也的矿车。 这到底是为什么呢? 答案已经很明确了: disystate也是在java1.13扁平化后由两个标签组合而成的。 那,这两个标签是什么呢? ∵block+data=blockstate 又∵blockstate=disystate ∴block+data=disystate 既然我们通过数学的思维得出来了答案,那就去试一试: \/summon minecraft:minecart ~~~{customdisytile:1,block:“minecraft:diamond_block“} 执行该指令,我们会发现—————— 又是一个空空如也的矿车!!!!! 很明显,数学思维在这里单枪匹马是不行的,我们得弄个帮手: 语言学 -what does “disystate“ mean in chinese? -it means “显示状态“ -what does “blockstate“ mean in chinese? -it means “方块状态“ 一个是“显示状态”,一个是“方块状态”。它们的用途都是设置方块,但一个名字含“方块”,一个不含。 这就说明了什么? “显示状态”其实是把方块省略了!其真正的全称是“显示方块状态”! 好!既然: 方块(block)+data=方块状态 那么: 显示方块(disyblock)+data=显示方块状态 按照结果,我们再来试下: \/summon minecraft:minecart ~~~{customdisytile:1,disyblock:“minecraft:diamond_block“} 执行,你就会发现...... ...... ...... 咋还是个空空如也的矿车! ...... ...... customdisytile的作用是“是否显示方块” 如果我们把customdisytile和“是否显示方块”进行一个配对,那么: custom——是否 disy——显示 tile——方块 把“是否”去掉,就变成了: disytile(显示方块) 这和我们的disyblock是一样的意思。 那么......使用disytile代替disyblock会发生什么? \/summon minecraft:minecart ~~~{customdisytile:1,disytile:“minecraft:diamond_block“} 执行,你就会获得一个装着钻石块的矿车...... ............! !!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 没错,我们成功了! 在扁平化中,是disytile和disydata合并成了disystate! disytile(字符串):设置显示在矿车里的方块。 在更老的版本(大概是矿车id还是minecartrideable时。矿车id改为minecart时已经是1.11版本了,这个版本也是方块状态出现的版本),disytile还支持方块数字id,比如\/summon minecartrideable ~~~{customdisytile:1,disytile:1}就会生成一个载着石头的矿车。 在1.8版本以前,disytile只支持方块数字id(因为1.8才更新了方块英文id)。 disydata(数值,值类型不知道):设置显示在矿车里的方块的数据值。 这就是1.13以前的矿车共通标签。 ——第四节:结束 在结束的时候,我要说一些东西。 一.上一章的小剧场,张三、王五、刘一三人得出来了四个结论。其中: data在教程\/下落的方块里并未提及,但应该是和properties一样,值为复合标签,代表该方块的方块状态。 其实是错误的。data在minecraft 1.11之前就出现了,而方块状态的加入时间是minecraft 1.11,时间上根本不对。所以,data实际作用其实和disydata一样,设置该下落的方块其方块的数据值。 二.minecraft wiki 中文中这样说道: 1.13——17w47a——重命名 fallingsand 到 falling_block. 实际上其重命名的时间是在1.11版本,和矿车被重命名的时间是一样的。 三.如果你使用浏览器的“检查”来打开矿车共通标签的页面(minecraft-zh.gamepedia.\/temte:nbt_inherit\/vehicle\/temte),再点开历史,你就会发现一个神奇的东西: 这个页面的最后修改时间是2016年10月23日07:56,而minecraft java 1.12更新时间是2017年6月7日,扁平化都还没有,这咋就开始disystate了?时光穿越? ok,那么本章就到此结束了。 第189章 我们目前已经了解了许多nbt标签,也知道了使用\/summon生成一个自定义实体的正确方式。但我们还不知道一点: 该如何修改一个现成实体的nbt呢?比如这只粉红色的羊? 在基岩版,你可以使用blocktopograph等存档修改器。而在java版,你除了使用修改器,还可以使用专门的指令: \/data 但\/data这个指令是java 1.13扁平化时扁平出来的。在java1.13-1.8版本,还有一个更简单的指令: \/entitydata 相信大家看了这么多章之后,应该都知道entity是实体的意思吧?而data的意思相信弄过计算机的人都知道,是“数据”的意思。 这下子我们就知道entitydata的意思了:实体数据。 意思知道了,那么我们该如何使用它呢? 正如上文所说,很简单。这条指令,只有两个参数: \/entitydata <实体:目标选择器><要添加或覆盖的数据标签> 目标选择器就不用说了,我们只需要看看“要添加或覆盖的数据标签”是什么东西就行了。 举个最简单的例子: \/entitydata @e[type=!yer]{health:0} 执行该指令,游戏将会给除玩家以外的其他实体添加一个{health:0}的标签,如果添加的对象已经有了这个标签,将会覆盖这个标签(同时聊天框会出现一大串的信息——实体数据已更新:{xxxxxxxxx:xxxx}.....。这条信息可以用来查看某个实体的nbt标签,但当游戏规则sendmandfeedback为false时并不会显示。)。比如你在执行指令前放了一个矿车,执行指令后矿车什么事情都不会发生,只不过nbt多了一个没用的{health:0}而已。但如果你旁边有只羊,执行指令后这支羊将会死亡,因为它的health被覆盖为0,因此游戏判定它死亡了。 这条指令的效果相当于\/kill @e[type=!yer]。但与\/kill不同的是,只有该指令选中的生物才会死亡,其他被选中的实体则不会受到影响,因为只有生物才有health值且会识别它。 这就说明了什么?\/kill并不能精确选中生物并杀死,但\/entitydata却可以。 是不是很简单? 但问题就来了。 使用刚才的指令后,这个矿车的nbt就变成了: {motion:[0.0d,-0.0d,0.0d],uuidleast:-l,health:0,invulnerable:0b,air:300s,onground:0b,dimension:0,portalcooldown:0,rotatlon:[0.0f,0.0f],falldistance:0.0f,uuidmost:l,pos:[-30.5d,4.0625d,-1131.5d],fire:-1s} 可以发现health标签被添加到了第一层,生物的health标签也在第一层。但如果我们需要替换的标签在第二层甚至是第三四层,该怎么办? 假设这里有一个id是genshin_impact的实体,其nbt是: {id:“genshin_impact“,uuidmost:l,uuidleast:-l,motion:[0.0d,-0.0d,0.0d],pos:[72.25d,65.7265d,271.5d],physcal_power:20,physcal_power_max:205,sex:1,health:,health_max:,role_id:“barbatos“,equipment:[{id:“chicken_mushroom_skewer“,value:15}]} 现在,我们要把equipment中的id标签的值从chicken_mushroom_skewer改为adeptus_temptation,该怎么做? 或许有人会这样做: \/entitydata @e[type=genshin_impact]{id:“adeptus_temptation“} 但其实这是错误的,这只能把该实体从genshin_impact变成adeptus_temptation。因为你这只写了一层,而真正你要改的id标签在equipment这个标签中。所以你要: \/entitydata @e[type=genshin_impact]{equipment:[{id:“adeptus_temptation“]}} 这样子,游戏才会正确的找到你要修改的id标签,然后将其值改为adeptus_temptation。 所以,“要添加或覆盖的数据标签”就是填你要修改的标签的nbt路径+标签,就像是文件的路径。“要添加或覆盖的数据标签”值的最外层“{}”就相当于根目录,对应目标实体nbt最外面那一层“{}”。 现在懂了吧? 但本章还未结束。或许有人会有这么个疑问: 为什么只有“添加和覆盖”而没有“删除”呢? 答案很简单,nbt标签不支持删除,所以你给矿车添加的那一个没有意义的health标签就永远删不掉了——除非你打掉矿车。 使用\/entitydata来添加或修改数据标签还有一个规则:如果修改的数据标签值类型为字符串,那么这个字符串里面不能空空如也。 这就是\/entitydata的全部内容了。 第189章 张三刚刚费尽千辛万苦打死了一个在水中拿三叉戟射他的溺尸,并获得了一把残三叉戟。他试了试这个三叉戟,发现按右键是可以丢出它的。于是张三尝试了一下,“听”的一声,三叉戟就丢了出去。“当”的一声,三叉戟掉了下来。 三叉戟可以右键扔出,像这样可以右键扔出的东西,在minecraft中还有雪球、鸡蛋。而箭这种需要用弓或弩射出的也是类似于这种东西。 这种可以射出、扔出、发射出的东西,我们给了他们一个总的称呼:弹射物。 既然都是弹射物,那肯定就有“弹射物共通标签”。 弹射物共通标签说白了就只有三个东西:两个布尔值一个int整形数组。 首先我们看看这两个布尔值,它们分别是: hasbeenshot(byte字节型:1 或 0) leftowner(byte字节型:1 或 0) hasbeenshot这个标签在弹射物最开始射出时为0(false),当该弹射物实体存在超过1游戏刻时会改为1(true)。为什么要这样?因为这样,游戏才能确保让你只射出去了一次该弹射物(这是一个游戏事件:projectile_shoot)。如果没有这个标签会怎么样? 假设张三装了一个模组,该模组会在玩家每使用弹射物一次时,在玩家头顶20格处生成一个落地就会消失的铁砧,以增加游戏的挑战性。该模组是这样判断玩家使用弹射物的: 玩家右键射出弹射物时,会触发一个游戏事件:projectile_shoot。模组监测到该事件被触发,就立刻执行生成铁砧的指令,然后就完成了这个玩法。 如果没有hasbeenshot这个标签,当张三右键扔出刚才那个三叉戟时,游戏就会开始每一游戏刻都触发一遍projectile_shoot事件,模组每一游戏刻都监测到projectile_shoot被触发,最后导致张三只能走不能停,甚至需要躲进矿洞里才能避免被铁砧砸死。这就是没有这个标签的后果。 那leftowner呢?这个比hasbeenshot要好理解些。当弹射物刚刚被射出时,它此时的碰撞箱和射出者的碰撞箱是重复的。游戏总不可能刚开始检测到碰撞箱重复就认为是弹射物打中实体吧?所以,为了防止张三刚刚扔出三叉戟就被三叉戟给刺死,leftowner最开始的值被设定为0(false),直到完全射出去之后再改为1(true)。 那这个标签这样做会发生什么?这个标签的用途就是设定该弹射物是否会与其他实体碰撞(简而言之就是会不会打中其他实体)。所以游戏才会用这个标签来避免发生乌龙。 最后,这个int整形数组是:owner。它的作用很简单:储存丢出该弹射物的人。它不一定存在,比如箭的nbt内就(好像)没有这个(作者看箭的nbt里没有)。那它有什么用呢? 举个例子。java的死亡信息比基岩版的死亡信息要丰富(且搞笑)很多。比如张三用这个三叉戟杀死了李四,那么将会: 李四被张三刺穿了 为什么游戏知道这个三叉戟是张三射出的呢?答案就在于owner存储了张三的uuid。翻一下这个三叉戟的nbt,你会发现这么一条: {owner:[i;,,-,]} 其中,[i;,,-,]就是张三的uuid。 但别忘了一件事情。1.16版本是把uuid高位和低位合并成了一个新的整形数组uuid。那在1.16版本以前,owner是什么呢?难不成是{owner:{uuidmost:xxx,uuidleast:xxx}}? 都不对。实际上这比你们想的要简单许多。假设张三刚刚不是在1.16版本刺穿李四的,而是在1.13版本,那么你将会发现owner变成了: {ownername:“张三“} 其中,“张三”是张三的游戏id。没错,你没看错,是游戏id! 好啊你个mojang,这么偷懒,连uuid都不用了,直接上玩家名啊。 吐槽归吐槽,我们还是要研究一下owner能搞出什么效果。 末影珍珠可以传送玩家。但当发射器射出末影珍珠时,反而传送不了发射器。这最主要的原因就是末影珍珠触碰到方块确定要传送的实体时是看owner里存储的实体uuid的,而发射器不是实体所以没有uuid。如果在末影珍珠还在飞行的时候更改owner存储的值从[i;,,-,]到[i;-,-,-,-],会发生什么? 李四落地过猛 这就是owner的用法之一。 第189章 我们都知道实体有实体共通标签,实体中的弹射物有弹射物共通标签。箭属于弹射物,它像矿车一样,拥有许多种类(额......实际上,除了光灵箭以外,其他的箭只是药水效果不同而已)。既然矿车拥有自己的共通标签,那箭呢? let us open minecraft and have a look. 我们打开1.12.2版本,一进游戏就先往天空射一发,然后在箭落地之前快速敲下“\/entitydata @e[type=arrow]{have_a_look:1b}”,然后这支箭的nbt标签就多了一个: have_a_look:1b 的标签,同时我们也获得了这支箭的nbt标签: {motion:[-0.0d,1.d,-0.01 d],damage:2.0d,shake:0b,xtile:-1,uuidleast:-85 l,inground:0b,pickup:2b,invulnerable:0b,air:300s,onground:0b,dimension:0,portalcooldown:0,rotation:[-135.f,89.0f],life:0s,falldistance:0.0f,intile:“minecraft:air“,uuidmost:-l,indata:0b,crit:1b,pos:[651.d,57.0d,41.00d],have _a_ look:1b,ztile:-1,fire:0s,ytile:-1} 看着有点晕是吧?好,那我们归纳一下。 在这串nbt内,除了我们的have_a_look标签,其他的标签一共有24个。分类一下,可以得到: tags mon to all entities={motion,uuidleast,invulnerable,air,onground,dimension,portalcooldown,rotation,falldistance,uuidmost,indata,crit,pos,fire} unknow tags={damage,shake,inground,pickup,intile,indata,crit,ytile,ztile,xtile} 这些标签中一共有10个我们还不知道是个啥,那今天我们就来仔细研究研究。 “damage”这个单词是“损坏”的意思,可作为名词或动词。但实际上按照这个标签的用途来说,它在这应该是个使动用法的谓语动词(????):使......损坏。再看看上面这串nbt,它的值是“2.0d”,最后的这个“d”,说明damage的值是双精度浮点数。 这标签的用途到底是什么?我们来个反向思维,damage的主语在这边应该是箭,即: arrows damage ......(箭使.......损坏了) 箭会使什么东西损坏?肯定是射中的实体啦!所以damage的作用就是: 设定箭将造成的伤害。 上面nbt中damage的值是2.0d,就代表着这个箭射中实体将造成2滴血(1颗心)的伤害。由于是双精度浮点数的值,所以这不一定是个整数。这个值会随着发射该箭的武器所有的力量附魔等级而变化,具体是力量附魔每高一级,就会增加0.5的值。假设你用一个附魔了级力量的弓发射这支箭,那么该值将会是: .0d(x0.5+2.0) 等等,实际上还要再加一个0.5,因为只要一把弓附魔了力量,不管是多少级,都会额外加上0.5,然后再加上(0.5x力量等级)。所以,实际上的值应该是: .5d 实际上箭造成的伤害不会那么低。箭的伤害还有被箭的速度影响,具体公式如下: v箭xdamage+暴击伤害=真实伤害 但还有一些情况伤害是个定值,如发射器射出的箭伤害一定是3滴血。 damage是这样,那接下来的shake又是何物? shake的意思是“摇”,这个比较难猜,就直接上答案: 当箭击中方块时,shake将会设定为7(单位为游戏刻)。在shake还未降为0时,就是箭的“抖动状态”,玩家此时不能捡起箭,需待shake为0时,方可捡起。 上面nbt中的shake值为0b,b就说明这是字节型数值。这个0,说明这支箭可能还在飞行,也可能已经落地超过0.35秒了。 那该如何判断一支箭是否落地了呢? ground的意思是“地面”,作为动词时有“着陆”的意思。上面,我们归纳出的第三个我们还不知道是干啥的nbt标签是“inground”。in the ground是一个短语,和on the ground意思差不多,都是“在地面”的意思,只不过前者更注重于强调“接触”。 那“inground”的作用大家应该猜到了吧?即: 箭是否接触地面。 上面的nbt标签中,inground的值是: 0b 说明inground的数值类型为byte(字节型),同时这个0(false)也说明了这支箭还在飞。如果这里的值不是0,而是1(true),那就是接触地面了。 当一支箭接触到地面,就代表玩家可以捡起它。但,众所周知,小白射出的箭玩家是不能白嫖的,你知道这是为什么吗? 你肯定不知道,但看完下面这一段,你就知道了。 实际上,不光是小白的箭无法捡起。当你开启创造模式用弓射一发再调成生存时,你会发现你照样无法捡起创造模式射出来的箭。 为啥? pickup这个单词的意思是“皮卡”,但这边应该把它拆分成pick up(捡起)。 既然pick up的意思是捡起,那么就是对捡起的设置咯? 对! 在上面的nbt中,pickup的值是2b,b说明这也是一个byte字节型标签。那这个2说明了什么? pickup的值你翻遍整个minecraft之后会发现只有三种: 小白射出的箭——0 你在非创造模式射出的箭——1 你在创造模式射出的箭——2 结合你玩minecraft的经验和作者上面分享的发现,可以得出: 非玩家生物射出的箭:0——不可被玩家捡起 非创造模式玩家射出的箭(发射器也算):1——可被除旁观者模式外其他模式玩家捡起(注:wiki上言“可以被玩家在生存或创造模式中捡起”,未提冒险模式,但作者实测冒险模式也可以捡起) 创造模式玩家射出的箭:2——只可被创造模式玩家捡起 现在我们可以回答上面的问题了: 这个2说明了这是一个创造模式玩家射出的箭 (注:用指令生成的箭pickup值也是0,即不可被捡起。推测是游戏本身产生的箭都不可以被玩家捡起) ........ 在之前,我们遇见过两个在1.13扁平化中被合并的nbt标签,这两个标签相信大家还记得,它们是: disytile+disydata=disystate(矿车共通标签) block+data=blockstate(下落的方块) 现在,我们在1.12.2版本的箭共通标签遇见了: intile和indata 这两个nbt标签和我们之前遇见的那两个标签在未合并之前的构造非常相似,那么它们是否在1.13版本中被合并了? disystate和blockstate有个共同点,就在于他们都是与方块有关系。合并之前,它们都分别有一个用来表示数据值的标签:disydata和data。数据值在1.13版本中被删除,所以这种类型的标签也就合并了。 indata和disydata、data一样,末尾都有一个“data”,那indata是否就是表示方块数据值所用呢? indata如果真是表示数据值,那intile呢?是不是用来表示方块id? 您别说,还真是。 在上面的nbt中,这两个标签的值分别是: intile:“minecraft:air“ indata:0b 你看,这minecraft:air不就是空气方块吗?这“0”不就是方块数据值吗? 这两个标签存的是啥我们知道了,但用处呢? 我们已经知道这支箭是飞在空中的,既然这里是空气方块,那么这两个的作用难道是....... 这支箭所处的方块? 您别说,您又对了。这两个标签的作用还真是这样的。 但我们还没有回答上面的问题呢。实际上的确是被合并了。至于合并成了什么东西....... 已知block+data=blockstate,block=tile,求单词式intile+indata的单词值。 解: intile+indata=in(tile+data)1 将block=tile代入1,得 intile+indata=in(block+data)2 将block+data=blockstate代入2,得 intile+indata=inblockstate ∴intile+indata=inblockstate 1.13版本扁平化过后,intile和indata被合并成inblockstate(值类型:复合标签),内含两个nbt标签: name(字符串)——该方块的id propertie(复合标签)——该方块的命名空间 ——方块状态名称:值(类型:字符串) ...... crit这个单词的意思是“暴击”。在上面的nbt中,crit标签的值是: 1b 说明crit标签的值类型是byte字节型。既然值类型是字节型,那就说明这个标签的作用不是确定这支箭暴击的伤害,而是这支箭是否会造成暴击。 所以,这支箭会造成暴击,因为它的crit值是1。 crit标签在1.11版本才被添加,1.11版本前没有这个标签,这需要注意一下。 最后,我们还剩下三个我们还未曾见过的标签: xtile,ytile,ztile 这三个标签在上面的nbt中值都为-1,且没有类型字母,应该是long长整型。并且它们三看起来跟坐标有关,而且坐标的三个值也是长整型...... 首先,我这边说一点,这三个标签不是箭共通标签内的,它们还出现在1.11以前的鱼竿浮标和火球类实体(如火焰弹,凋零之首)中。至于它们三有什么用,我们以后再了解。 现在我们知道箭共通标签内有这些东西: damage、shake、inground、pickup、intile和indata(inblockstate)、crit,那这就是全部了吗? 不,在更新的版本中,还有一些更新的标签: piercelevel(byte:字节型)——中文wiki介绍是“箭能射穿实体的时间长度”,但这好像并不是这个用途 shotfromcrossbow(byte:字节型[true|false])(1.14+)——表示这支箭是否来自于一把弩 soundevent——击中东西时触发的声音事件 soundevent我们先不用管。这个piercelevel我本人也搞不懂,返回的值一直是0b,这可能是在击中实体的那一瞬间才可能会变化。剩下的这个,就是shotfromcrossbow。 shotfromcrossbow很简单,上面都介绍过了,相信只要是看得懂的都能懂吧? 总之,只要shotfromcrossbow的值为1b,那么这箭就来自一把弩,0b则来自其他的东东。 这就是“箭共通标签”。 第189章 看!这草方块上漂浮着一个黑中带橙的小球球。 这是什么东西?你捡起来,一看:哦吼,火焰弹。 相信大家第一眼见到火焰弹时,看到这个“弹”字,都误以为是某种炸弹吧?其实稍加研究就知道,这东西除了远程点火以外,基本没啥用。 真的是这样吗?火焰弹在发射时,方向是不固定的,但可以通过某种技术来实现“定向火焰弹”,进而造出“火焰弹无线信号传输”。只不过这就不是指令了,这已经是红石技术了,具体想要深入了解的可以看看:av《没有电磁波?!但我们依然可以开发无线电技术(无线红石技术入门)》 既然火焰弹在指令方面还没什么大用,那为什么我要说这东西? 仔细想想,火焰弹到底是个啥? 肯定是个实体啦!那么是实体中的什么呢? 弹射物啊! ? 我们目前已知的弹射物,它们都会受到重力影响,所发射出的路径是一个标准的抛物线。 但火焰弹发射后并不会受到重力影响,且速度(看起来)保持不变,以一种无视空气阻力向全世界物理学家挑衅的态度一直飞,直到撞到某个东西或因存在时间过长而被删除。 所以,火焰弹到底是什么? 弹射物啊!那不然是什么。 火焰弹其实也是弹射物,它属于弹射物中的“火球”。属于火球这类的弹射物还有: 恶魂火球、烈焰人火球、凋零之首、末影龙火球 火球有一个共通标签,即“火球共通标签”,内容很简单,就两个东西: power(值:列表) direction(值:列表) 这两个标签的内容是一样的,都是一个列表,内有三个对应x、y、z三个轴的值,这三个值类型都是双精度浮点数。更形象亿点来说,是这样: power:[0.00d,0.00d,0.00d] direction:[0.00d,0.00d,0.00d] 它们除了标签名称不一样之外,唯一不一样的,就只有它们的功能了。 我们知道,一个物体的运动过程中的速度按变化可分为两种:变速运动和匀速运动。变速运动中,还有匀变速运动,即加速度不变的运动。按运动轨迹也可分为两种:曲线运动和直线运动。就在刚刚,张三对着服务器主城来了一发火焰弹。如果你刚巧把这段录下来了,那好!赶紧以0.05x倍数播放这段录像,仔细观察这个火焰弹,你会发现: 这火焰弹的初速度(v0)为0,随后加速以直线运动的方式最终以极快的末速度(vt)撞击了主城的木质大门,用时(t)87游戏刻,中途间加速度(a)似乎保持不变。你应该知道,火焰弹的这种运动,叫做:匀加速直线运动 其中,不管是初速度还是末速度,它都存储在火焰弹的motion标签中,但这个加速度存储在哪呢? 答案很简单,必然是power和direction之一。而power有“供以动力”的意思,自然就是它了。 power的作用就是设定火球的加速度。在火焰弹发射时,游戏会在一定范围内随机生成power的三个轴的加速度值,这就是火焰弹为什么每次发射的方向都不一样,生成后这三个值就固定了,除非外力修改。同时,火焰弹的初速度为0。发射后,每游戏刻,游戏都会将power的三个值加到direction的三个值中,让火焰弹以匀加速直线运动的方式运动。 等等,为什么加的是direction而不是motion呢? 答案仍然非常简单,direction和motion的作用一样,且两者数据互通。更形象点就是: direction=motion 至于mojang为何要这么搞......实际上minecraft 1.16版本更新它们就(才)意识到这个东西是多余的。于是在1.16版本,没有中间商赚差价,power的值就直接加到motion里了。 这就导致一个很离谱的事情:当你在玩1.16以下版本的minecraft时,如果你要用\/summon生成火焰弹,你不能直接: \/summon small_fireball ~~~(注:火焰弹作为实体形式的时候叫做“小火球”) 你得: \/summon small_fireball ~~~{power:[0.0d,0.0d,0.0d],direction:[0.0d,0.0d,0.0d]} 这样子才能生成出一个火焰弹(还是静止的)。 而在1.16版本以上,没问题了,你只需要: \/summon small_fireball ~~~{power:[0.0d,0.0d,0.0d]} 唉,就一点儿问题也没有,甚至nbt你都不用加,直接\/summon small_fireball就行了,系统直接给你默认全为0。 火球中,除了烈焰人火球之外,其他火球类实体都是像火焰弹一样初速度为0匀加速直线运动的。烈焰人火球是匀速直线运动(但神奇的是烈焰人火球本质上也是火焰弹)。 似乎这一章可以到此为止了。但如果你仔细研究,你会发现一个问题: 为什么火焰弹是“小火球”呢,大火球去哪了? 额,没有大火球,但有火球(fireball),这“火球”就是那个天天在天上鬼哭狼嚎的恶魂发射的。火球相比小火球就厉害了,你应该知道火球是可以打回去的,指令生成的火球也一样,而且也会破坏方块。 好,那么本章就到此为止了。 ...... ...... ...... ...... ...... ...... ...... ..... .... ... .. . “张三~张三~你过来一下” “啥事啊?” “看!我们腐竹研究出来一个新花样” “腐竹把服务器升级到1.17了?我咋不知道?” “还在1.12.2啦,你又没用上java16” “那这是怎么一回事?这工作台为什么会发光?” “我也不知道是怎么一回事,去问问刘一看看?” “你自己去问吧,我要研究研究新版本,没空跟你聊” 王五见张三又开始在那刷籽岷的视频,只好自己向刘一发起了传送请求。刘一那边也是非常热情,刚一发出去就同意了。很快,王五就来到了刘一的火柴盒。 “我说老兄,你这泥土屋子就不翻新一下吗,顶上的茅草都两米高了”王五一过来就吐槽了一句。刘一也是习惯了,等他说完就直接切入正题:“这次你又有什么问题?” 王五把发光的工作台给刘一描述了一下。刘一不愧是一位有经验的大佬,稍微想了一下,就想到了答案:“实际上要做出这样的效果并不难,只需要找一个可以发光的实体,将其静止,再放个工作台盖住就行了。” “而可以发光的实体中,也就火焰弹的实体可以做到,即小火球。” “小火球可以发光,将其静止后放上工作台并不会消失,玩家也点不到” “原来如此!”王五像是发现了新大陆一样。 回到地下基地后,王五向张三解释了其原理,张三听完后“哦”了一声就继续沉浸在1.17新版本当中。 “看来,我也应该要多关注一下新版本了”王五想着想着,也和张三一起看了起来。 ...... 第189章 这儿有一只土猪,它的梦想是那颗白菜。 但今天我们并不是要研究这只土猪,而是在minecraft中的猪。minecraft中可没有白菜。 在生存前期,粮食紧缺,玩家们一般会直接把这只猪杀死;在生存后期,粮食的获取是长期的事情,因此玩家们经常种田,也就有了各种自动化红石机械。 但种田获得的是素食,长期吃素会导致营养不良,所以玩家们还需要一种肉食来源。这时,他们就会另找来一头猪,拉到这只猪旁边,然后喂几根胡萝卜。几秒下来,就多了一只小猪。 这个过程,我们称之为“繁殖”。 在minecraft中,可繁殖的生物不只有猪一种。据“成双成对”成就统计,截至2021年7月6日,minecraft中一共有19种可繁殖的生物,它们是——鸡、牛、哞菇、猪、兔子、羊、海龟、马(已驯服)、驴(已驯服)、骡(已驯服)、羊驼(已驯服)、豹猫、狼(已驯服)、猫(已驯服)、狐狸、熊猫、蜜蜂、疣猪兽、炽足兽。 既然有这么多生物可以繁殖,那么它们的nbt是否也有共通之处呢? 有的! 看看这只1.12.2版本的猪,在使用了entitydata给它添加了一个have_a_look标签后,我们获取到了它的nbt数据: {hurtbytimestamp:0,attributes:[{base:10.0d,name:“generic.maxhealth“},{base:0.0d,name:“generic.knockbackresistance“},{base:0.25d,name:“generic.movementspeed“},{base:0.0d,name:“generic.armor“},{base:0.0d,name:“generic.armortoughness“},{base:1.0d,name:“forge.swimspeed“},{base:16.0d,modifiers:[{uuidmost:l,uuidleast:-l,amount:0.0d,operation:1,name:“random spawnbonus“}],name:“generic.followrange“}],invulnerable:0b,fallflying:0b,forcedage:0,portalcooldown:0,absorptionamount:0.0f,saddle:0b,falldistance:0.0f,inlove:0,deathtime:0s,handdropchances:[0.085f,0.085f],persistencerequired:0b,age:0,motion:[0.0d,-0.0d,0.0d],leashed:0b,uuidleast:-l,health:10.0f,lefthanded:0b,air:300s,onground:1b,dimension:0,rotation:[267.f,0.0f],updateblocked:0b,handitems:[{},{}],armordropchances:[0.085f,0.085f,0.085f,0.085f],uuidmost:-l,pos:[618.d,4.0d,47.d],have_a_look:1b,fire:-1s,armoritems:[{},{},{},{}],canpickuploot:0b,hurttime:0s} 看着很晕是吧?我们简化一下,删去已知的nbt标签,剩下了这么几个: {forcedage:0,saddle:0b,inlove:0,age:0} 其中,除了saddle以外,其他都是属于“可繁殖的生物共通标签”。 saddle(布尔值)的作用是确定这猪背上是否放了个鞍,有鞍为1,没鞍为0. 不难发现,在这“可繁殖的生物共通标签”中,有两个nbt标签(forcedage和age)其标签名中都有单词“age”。age这个单词的意思大家都知道,是年龄的意思,那这两个nbt标签有啥用呢? 看,那儿有两只猪正在村民种的土豆菜地里晃悠。赶紧过去收割一些成熟的土豆,然后喂给这两只猪吃。很快啊!不到几秒就出现了一只小猪,让我们看看这只可爱的小猪的nbt吧! {forcedage:0,inlove:0,age:-} 这只刚生出来的小猪,其age值为-。在《minecraftwiki:母猪的产后护理》一书中(实际上没有这本书啦),明确的写到:“幼年猪在没有食用任何食物的情况下,需要花费一整天时间长大。可以通过喂食来加快速度,一次喂食加快10%。” minecraft中的一天为20分钟,换算成游戏刻即20x60x20=刻,而age的值是-,所以age的作用是? age(int整形)的功能是表示该生物的年龄,幼年时为负值,并随时间流逝不断增加直到0。当该生物age值达到0时,判定该生物成年,并停止增加。 幼年猪要长大需要刻,即age初始值为-。这只小猪的age值为-,说明它已经20.7秒大了。 那forcedage有啥用? 刚刚引用的那段话最后两句讲到喂食可以加快生长速度,让我们试一试。 作者喂给这只小猪两个土豆,nbt就变成了: {forcedage:4400,saddle:0b,inlove:0,age:-} 刚刚花去的时间不到二十秒,这只猪的age值就增长了4733(236.65秒),forcedage值也变成了4400,这说明给小猪喂土豆是可以加快生长速度的,这加快的值被forcedage统计了,并且也加到了age里面。 但一次喂食是加快10%,两次喂食岂不是加快了20%或19%,即4800或4560。但这儿却只加快了4400,稍微有些偏差,这是怎么一回事? 经过作者的多次试验,发现每次喂食并不是一定加快10%,而是有一个小幅度的浮动,所以这本《minecraftwiki:母猪的产后护理》并不一定完全准确。 那inlove又有何用? 作者写着写着,这只小猪长大了。此时作者给了它一个土豆,然后就发现它的nbt标签变成了: {forcedage:4400,saddle:0b,inlove:577,age:0} “if you hold food in your hand, they follow you around. if you feed them, they enter “love mode“. two animals in love mode = babies.(只要你手上有食物,它们就会跟着你。如果你喂它们,它们就会进入“求爱模式”。两只求爱的动物=下崽。)”——notch notch的这番话中提到了一个“love mode(求爱模式)”,这个求爱模式是在喂食之后进入的,inlove也是在喂食之后变化的。而且,inlove直译是“在爱里”,意思类似“求爱模式”,难不成? 没错,inlove就是notch文中提到的求爱模式在nbt标签中的具体表现,这个“求爱模式”时长2分钟,即600游戏刻。进入“求爱模式”后,再次喂食不能将inlove值重置为600。在“求爱模式”中,生物会持续散发红色粒子。当两只进入求爱模式且类型相同的生物相距8格,它们便会靠近,然后的事大家都知道,最终求爱模式结束。 inlove值随时间减少到0时,求爱模式也会结束。 这只进入求爱模式的猪,多了两个我们未曾相识的nbt标签: {lovecauseleast:-l,lovecausemost: 0l} 唉,这least,这most,这一长串的long长整型值——这不就是uuid吗? 没错,这就是uuid,那这uuid是谁的? 是这只猪的爱人的uuid。 ?不对啊,这世界的“生物自然生成”已经被关了,猪只有它一个人,那它爱着谁? 作者寻找了一下这个uuid的所有者,结果发现这是个空号。 嘶——细思极恐啊。 现在,我们已经了解了age、forcedage、inlove和lovecauseleast、lovecausemost这五个nbt标签,这些标签就是“可繁殖的生物共通标签”的全部内容。众所周知,1.16版本uuidleast和uuidmost合并了,所以在minecraft java1.16及以上版本,lovecauseleast和lovecausemost被合并成了lovecause标签(整形数组)。 我们按照minecraft生物一生的发展来对这些标签进行分类,可以分出: 幼年(20min)——age、forcedage 成年——age:0 单身——inlove 结婚——lovecauseleast、lovecausemost(<java1.16)|lovecause(≥java1.16) 生子——??? 可以发现,生物繁殖之后所用的nbt标签我们还不知道,但“可繁殖的生物共通标签”就五个标签,所以生物繁殖之后所用的nbt就在这五个标签之中。 当然,也可能根本就没有用到。只不过,在下结论前,请最后看一遍《minecraftwiki:母猪的产后护理》,其中有这么一段话:“猪繁殖过后,两只猪都会进入繁殖冷却期,期间通过喂食将无法进入求爱模式。繁殖冷却期长达五分钟,五分钟过后将会自动回到正常期,可以再次进入求爱模式。” 嗯,按mojang的尿性,这五分钟绝对有nbt标签存着。让我们动手看一看究竟是哪个nbt存着这繁殖冷却期的剩余时间。 作者又弄出一只猪,让这两只猪繁殖了一下,然后拉开其中一头,仔细看它的nbt: {forcedage:0,age:5416,inlove:0,lovecauseleast:-l,lovecausemost:l} 哦吼,发现没有!age的值是5416!我们知道,5分钟换算成游戏刻是5x60x20=6000刻。所以,age还有一个用处: 当生物与另一只同种生物进行繁殖过程后,age的值将会变为6000,并随时间减少,为0时停止。age值减少期间,将是该生物的“繁殖冷却期”。 到这儿,“可繁殖的生物共通标签”才算全部讲完。哦老天爷,终于更了一章啊。 ....... ....... ....... ....... ....... ....... ....... ....... minecraft文言文版本真棒! ....... ....... ....... ....... ....... ....... we know how to use the tag “lovecause“,but when we fill the tag from the other kind of mobs'' uuid,what will happen? i experimented,but nothing happen. ....... 第189章 (注意,本章的侧重点在于java 1.8及之后的版本,1.8之前的版本本章并没有对其仔细研究,到时候会专门出一章来研究研究) 前面的一百多章节,讲了许多东西,但似乎漏了一个挺重要的东西。 想来想去,原来是调试界面还没讲。 既然第十四卷已经有19章了,那就新开一卷,放松一下,虽然还有许多东西没讲(比如自定义交易之类的,放第十六卷吧,村庄与掠夺更改的内容还得好好研究研究)。 在写本章时,作者为了检测各个minecraft版本调试界面的区别,分别使用了四个启动器加一个第三方客户端开了五个不同版本的minecraft java版,它们分别是:java1.7.10,java1.8,java1.12.2,java1.13.2和java1.16.5。因为minecraft wiki对于调试界面的历史变更记载起码有一半漏掉了,所以本章但凡有提到版本变更的,大部分都是作者自己测出来的一个比较模糊的范围。 进入正题。首先,什么是“调试界面”? 众所周知,在minecraft java版中,按下f3(mac电脑和一些笔记本电脑是fn+f3),屏幕上就会出现一大堆东西。这一大堆东西让许多minecraft玩家直呼:“我看不懂,但我大受震撼”。 现在,请停止你的震撼,然后跟着我来从左上角开始一行一行看。 左上角第一行,显示的是游戏的基本信息,即:这个minecraft java的版本号是多少,启动器是什么,启动器版本号又是什么等。如果你是通过我的世界官方启动器启动的纯净minecraft版本(即无插件),那么这一行将会显示: minecraft 版本号(版本号\/vani) 这里的“vani”的意思是“纯净的”,即这个minecraft是纯净版本,没有装任何其他插件(这里的插件并不包含资源包、附加包,而是指forge之类的东西)。 如果你装了个forge,那么这里将会变成: minecraft 版本号(版本号\/fml,forge\/forge) (上面这一行是在1.12.2版本下测试的结果) 但是,有些插件并不会显示,比如optifine。 如果你像作者一样,使用的是hmcl(hellominecrafuncher)启动器,那么这儿将会显示: minecraft 版本号(hmcl 启动器版本号\/vani\/hmcl 启动器版本号) 如果你使用hmcl启动器并装了forge插件,那么将会显示成: minecraft 版本号(hmcl 启动器版本号\/fml,forge\/forge) 其他的一些minecraft启动器作者也进行了测试,结果如下: pcl2(in craftuncher 2):和minecraft官方启动器一样 bakaxl:minecraft 版本号(版本号\/vani\/bakaxl) 这是第一行,接下来请看第二行。 第二行的最前面你绝对看得懂,即fps(每秒传输帧数),大家口中的“帧率”。如果你连fps是啥都不懂......简单来说,fps数值越高,游戏越流畅,反之越卡。 后面就有些乱了。首先是个: (数值 chunk updates) 实际上这很简单,你把这串放进生草机里搅拌一下,就会得到: (数值个区块更新) 这本书看到这儿,只要你没有跳着看,区块是个什么你应该知道吧。 那“区块更新”又是什么东西? 答:当一个区块内有任何一个方块其nbt标签发生任何的改变,或者方块被破坏、放置、移动,这个区块就被视为发生了更新。 这个(数值 chunk updates)就是向我们显示目前游戏内有多少个区块发生了更新。 但可惜的是,1.15版本mojang将chunk updates移除了。 (数值 chunk updates)后面是一个“t:xx”。这个t的值对应了视频设置内的“最大帧率”值。如果游戏设置内的最大帧率值是120,那么这里将会显示成“t:120”。如果游戏设置内的最大帧率被拉到了最大,也就是“无限制”,那么这里将会显示为“t:inf”。(这里的inf是infinity无限的缩写) “t:xx”后面是一些单词,这些单词加上“t:xx”本身都是显示一些关于游戏画面的配置。 如果你在minecraft的“游戏菜单\/选项\/视频设置”里打开了“使用垂直同步”选项,那么这儿将会在t:xx后面多出一个单词: 1.8\/1.12.2\/1.13.2——vsync 1.16.5——vsyncfancy (vsync是vertical synchronization[垂直同步]的缩写) 同样的,对于“云”的设置也会显示在上面。在java 1.8.1以前,云的流畅和高品质是由“图像品质”选项控制的,1.8.1及之后云的流畅和高品质被独立到了“云”选项里。因为云有两种品质,所以当你打开云层时,显示的单词会有所不同。对了,对于“云”的设置其单词一定是显示在垂直同步后面的。 流畅: 1.8——fast clouds(这里的fast和clouds没有连起来是因为这儿的fast实际上并不只指云层是流畅品质,而是对应了“图像品质”选项里的流畅。当你把云关掉,你会发现fast还在这里,只是clouds消失了) 1.12.2\/1.13.2\/1.16.5——fast-clouds 高品质: 1.8——clouds 1.12.2\/1.13.2\/1.16.5——fancy-clouds 1.14的18w44a快照将“启用顶点缓冲器”选项移除了,并让顶点缓冲器在之后的版本中一直是保持开启状态。在移除这东西之前,只要你打开它,你就会在“云”的单词后面发现一个单词:vbo。 vbo是vertex buffer object(顶点缓冲对象)的缩写。在移除过后,调试界面中就再也见不到它了。 在作者打开的1.16.5版本中,在“云”的单词后面还有一个: “b:x” 这东西不知道是什么时候更新的,反正1.13.2版本没有见到。这个东西是关系到视频设置中的“生物群系过度距离”选项。这个选项可以选择0、3x3、5x5、7x7.....15x15一共8个级别的过度距离,分别对应“b:x”显示的0到7级。比如,如果你显示的是“b:2”,那么你的生物群系过度距离就是5x5(普通)。 第二行的内容还真多。接下来请看第三行。 1.13版本更新时,mojang在原本的第二行到第三行间插入了一行,将原本c开头的第三行挤到了第四行也就是这串: integrated server @ xx ms ticks,xx tx,xx rx 嗯......不对,我是单人游戏,哪来的延迟? 实际上这儿并不是告诉你单人游戏的延迟,而是告诉你: 游戏中的一游戏刻需要电脑耗费多长时间运算出来。(ticks是游戏刻的意思) 众所周知,1000ms=1s,20游戏刻=1s,一般情况下电脑是可以保证一秒满20游戏刻,即一游戏刻需要运算的时间≤50ms。作者之前测试了一下,作死重复执行\/execute at @e[type=item] as @e[type=item] run fill ~1 ~1 ~1 ~-1 ~-1 ~-1 air destroy,这行的ms ticks值立马飙到了1000ms多,也就是一游戏刻需要耗费1秒多的时间来计算。所以,这个ms ticks的数值在检测游戏有多卡时还是挺有用的。 后面的xx tx,xx rx显示的是客户端每秒发送(transport)和接收(receive)的包数。单人游戏还在发送接收包就挺离谱,而且就算关了匿名反馈也照样发送接收。发送给谁?接收的是哪个服务器的包?这些问题还有待研究。 在服务器中,这一行有些变化。作者进入了hypixel服务器,发现其变成了: “vani“ server,xx tx,xx rx 前面说过,vani代表着这个minecraft是没有加任何插件的。所以这儿的“vani”server的意思就是:该服务器并没有加任何插件。 第四行,也就是1.13版本之前的第三行,又是让人大受震撼的一行。 但只要你仔细一看,会发现这一行是由一堆“缩写:值”拼凑起来的,拆分开来就简单许多了: c:xxx\/xxxx (s)——视野内渲染的区段数\/已经加载的区块(不管强还是弱加载)所包含的区段总数量。注意,是区段数不是区块数!(?区段是什么个东西)(区段本身是16x16x16的立方体,一个区块在1.18更新之前一共有16个区段。区段可以通过f3+g显示区块边界查看区块上的蓝色线条来判断。) d:xx——对应游戏视频设置里的“渲染距离”。如渲染距离是12区块,那么将会显示成“d:12”。 l:xx——作者也不清楚,存在于1.8版本之后1.16.5版本之前,中文wiki上没有相关的描述,英文wiki倒是有:client-side blocks count that have light update to apply,但不解其意。 pc:xxx——等待成批处理(卸载)的区块数量(第一百二十章讲的区块卸载机制跟这东西有关系,建议回去复习,还是挺有趣的) pu:x——等待提交给显卡的更新数量。说白点就是:在一游戏刻内你视野内凡是有东西,不管是实体还是方块,发生了变化(更新)之后,都要呈现到你的面前,这时候就要将这个变化(更新)提交给显卡来处理成图像。这个pu就是记载本游戏刻将要给显卡更新图像的东西的数量。 ab:x——成批处理(卸载)区块时可以用的缓冲区数量 额,看起来拆分开来并没有简单许多。(估计很多人一遍过后看不懂,这一行确实挺难的,建议多看几遍消化消化) 但接下来的第五行,也就是1.13版本前的第四行,听我的,特别简单。 这一行主要是关于实体: e:xx\/xx——在视野中的实体数\/已经加载的区块所包含的总实体数 b:0——啥用也没有,估计是mojang哪位员工做这个的时候摸鱼了 在1.8版本左右还有一个: i:xx——不在视野中但处于已经加载的区块的实体数量。因为这个东西太鸡肋了,所以在1.8版本之后1.12.2版本之前不知道哪个快照更新时砍掉了。 下一行p开头也很简单: p:xx——渲染的粒子数量 t:xx——已经加载的区块所包含的总实体数,在1.16.5版本之前是“t:all:xx”,不得不说这和那个被砍掉的“i:xx”一样鸡肋。 第七行(1.13前第六行)只有一个东西,但看起来很高级: multiyerchunkcache:xxxx,xxxx(作者发现在1.16.5版本已经改为了client chunk cache) wiki上描述是“所能载入的最大区块数。”,但作者实测发现这还有个东西。 可以发现这儿有两个数值,但按照这个功能来说只需要一个数值就好,所以作者对此进行了深入研究,得出来一个严谨的结果: 这两个值中,前面那个值即是“所能载入的最大区块数”,受渲染距离影响,必定比渲染距离所加载的区块数量还要多,只要不改变渲染距离就不会变化,但目前尚不知到计算方式。后面的那个值,是“已加载的区块数量”,包含强加载和弱加载区块。 看来wiki也不过如此.jpg 在1.13.1版本之前,到这儿左边的第一大段已经完了。但1.13.1版本更新了个第八行: minecraft:xxxxxxxxx fc:xx 前面的这个带有“minecraft:”命名空间的单词,就是你所处的维度id。比如你身处主世界,那么这儿将会显示: minecraft:overworld 这个“fc:xx”,显示的是你所处维度有多少个被强制加载的区块(即使用特殊手段加载的区块,比如使用\/forceload加载的区块)。 (额,\/forceload在1.13.1被加入,这一行也是在1.13.1被加入......\/forceload真有牌面) (唉,为什么我的fc值是n\/a) 在1.15版本之前,到第八行左边第一大段已经完了,但mojang在1.14到1.15版本之间的某个快照更新中将一个新的东西插入到原本第七行和第八行的中间,这东西就是: serverchunkcache minecraft wiki上不确定这东西有啥用,但根据client chunk cache,我们可以大胆猜测这东西就是:服务器最大加载区块 但在服务器中这一行根本就没有显示,这个说法也就不攻自破。 那么本章就到这里了。 第189章 在上一章,我们了解了调试界面左上第一方阵的主要内容,可以发现第一方阵主要是关于游戏的一些参数设定。接下来,我们就要了解左边这一排剩下的内容。 第二方阵的内容就极其有用了,我们的坐标、区块、生物群系、光照强度等信息都显示在这儿。 不管版本怎么迭代(1.8到1.16.5),第二方阵的前四行基本上没有变化。这前四行具体是: xyz:xx.xxx \/ xx.xxxxx \/ xx.xxx——玩家的坐标信息,更精确的来讲是玩家脚底的坐标。 block:x y z——玩家脚底所处方块的坐标信息,相当于将上一行的xyz坐标向下取整而得到的结果。 chunk:x x x in xx xx xx——前者是玩家在所处区段内部的位置,区段内部坐标xyz都为0的地方是该区段内世界坐标xyz三个值相加起来最小的地方,即区段的下西北角;后者是玩家所在区段在整个世界的位置,相当于是将上一行block的xyz都除以16再向下取整的结果。(wiki上说是区块,但个人认为应该是区段) 可以发现,这三行都跟位置有关系,且本身互有联系。只需要知道第一行xyz的值,就可以算出来第二行和第三行的值。比如张三的xyz坐标是:-312.433\/76.00000\/212.782,就可以计算得出: block:-313,76,212 chunk:7,12,4 in -20,4,13 (关于玩家所处区段内部位置的计算方法: 设block的三个坐标分别为为x,y,z,那么玩家所处区段内部位置就是: x=x mod 16 y=y mod 16 z=z mod 16) 第四行——facing:方向(towards positive\/negative 坐标轴)(xx.x \/ xx.x) 这一行主要是你的朝向参数。 facing:xx——朝向的方向,即东南西北,这可以解决你在minecraft中分不清东南西北的问题。请记住,上北(north)下南(south)左西(west)右东(east)。 那个括号里的东西......还记得第五章吗?在第五章里,我讲到坐标的三个轴中,x和z轴分别对应了东西和南北。这儿的towards,就是显示你朝向的方向对应的是哪个坐标轴。比如: facing:west(towards positive x) 而那个positive\/negative,则是显示坐标轴的正(positive)和负(negative)。 最后的那两个值,是我们已经很久没有见到过的: (水平旋转角度\/垂直旋转角度) 希望你还没有忘记它们。 1.13.2到1.16.5这期间,第四行后面发生的变化特别大,所以接下来的内容均为1.14版本之前。 在1.14版本之前,第五行到第七行并没有什么大变化: biome:生物群系——显示玩家当前所处位置的生物群系,1.13扁平化后多了个命名空间(biome:命名空间:生物群系)。 light:总光照强度(天空光照强度 sky,方块光照强度 block)——第一个值是显示玩家脚部的总光照强度,包含天空光照强度和方块光照强度。括号里的两个值前者是显示脚部的天空光照强度,后者是脚部的方块光照强度。光照强度之类的东西之前的章节好像基本上没有提到,这里先简略讲一下。 ————光照强度 光照强度一共有16级,用0到15的整数表示。在minecraft中大致有两类:天空光照强度和方块光照强度 天空光照强度比较离谱,它在白天时有用,一到夜晚立马有个锤子用。 看起来到夜晚就没用挺正常的,毕竟太阳都落山了嘛。但如果真是这样的话,那就不用再特意加一句了。 实际上,不管是白天还是黑夜,天空光照强度只要你头上没有半透明或不透明方块挡着,永远都是15级!没错,夜晚还是15级! 方块光照强度就正常了。minecraft中,每个方块都有自己的亮度等级。方块发出的光其强度就是由该方块的亮度规定的。比如火把产生的光照强度就是14级。这种由方块产生的光照,就是方块光照,它的等级就叫方块光照强度。 方块光照就靠谱多了,刷怪需要的光照强度(1.18之前需内部光照强度≤7,内部光照强度=max(方块光照,内部天空光照))有一半就是靠它。 光照强度具有传递性,每次传递光照等级减一,直到为0。 回到正题。大致了解了光照强度之后,light的三个值你应该就看得懂了吧?注意,总光照强度并不等于天空光照+方块光照,而是等于(max(天空光照,方块光照))。 1.12.2\/1.13.2\/1.16.5——local difficulty:区域难度\/\/副区域难度(day x) 1.8——local difficulty:x.xx(day x) 第七行显示的是玩家所在区域的区域难度和生存天数,1.8至1.12.2期间不知道哪个版本又加了个副区域难度进去。区域难度是游戏难度的一个变种,每个区块都有自己的区域难度和副区域难度。 区域难度的计算极其复杂,它关系到你在当前区块累计停留时间、你在世界内累计的游戏时长、你的游戏难度设置和当前的月相(没错,这就是为什么第一天最危险的原因,因为第一天的月相是满月,满月对于区域难度的加成最大)。你的游戏难度设置规定了区域难度的上下限: 和平:0~0 简单:0.75~1.5 普通:1.5~4.0 困难:2.25~6.75 local difficulty的第一个值就是区域难度,而那个1.8版本没有的第二个值就是副区域难度。副区域难度是另一个影响游戏难度的参数。副区域难度的计算极其简单,它在代码中是这么计算的: if ( regionaldifficulty < 2.0 ){ value = 0.0; } else if ( regionaldifficulty > 4.0 ){ value = 1.0; } else { value =( regionaldifficulty - 2.0 )\/ 2.0; } 翻译: 如果(区域难度小于 2.0 ){ 值= 0.0;\/\/注释:这儿和下面的值都是副区域难度 }否则如果(区域难度大于 4.0 ){ 值= 1.0; }否则{ 值=(区域难度- 2.0 )÷ 2.0; } 括号内的day就是生存天数,只不过这个天数会受到\/time指令的影响(比如\/time set 0就直接变成day 0)。 在1.13扁平化之前,第八行是: looking at:x y z 即显示你指针选定的方块的坐标,当然超过一定距离就不显示了。 1.13扁平化后,这东西被拆分成了: looking at block:x y z looking at liquid:x y z 前者还是老样子,后者在一般情况下和前者一样。什么时候不一样呢?指向液体的时候,liquid一行会显示指向的液体方块的坐标,block一行会显示指向的液体后面的方块的坐标,扁平化前的looking at则没有这个看液体坐标的功能。 第八行在不指向非流体方块时会隐藏,第九行会在不指向方块或液体时隐藏。扁平化过后,这个显示所需要的与选定方块的距离被增加到了二十多格,隔着很远也能显示。 可惜的是,这两行在1.14过后到1.16.5之间不知道被哪个版本删掉了。 那么本章就到这儿了。...... ..... .... ... .. . 额,你知道吗,在1.14版本之前,如果你所处的y坐标大于256或小于0,那么第四行后面到looking at的所有行都会被一句:outside of world...替代。 第189章 在上一章中,作者提到了调试界面左边第二阵第四行之后的内容,在1.13.2到1.16.5版本期间发生了极大的变化。这一章,我们就要了解,到底发生了什么变化? 在1.16.5版本,第五行已经不是biome了。这一行得和下面一行,即第六行一起看: client light:光照强度(天空光照强度 sky,方块光照强度 block) server light:光照强度(天空光照强度 sky,方块光照强度 block) 不难发现,新版本是将light一行拆成了客户端光照强度(client light)和服务端光照强度(server light),实际作用和原本的light一样,只不过分成了两端。比较奇怪的是,当你并没有在玩服务器而是在单人游戏时,server light还是会显示,只不过会显示成: server light:(与上一行的天空光照强度一样 sky,与上一行的方块光照强度一样 block) 嗯,所以说为什么mojang不直接把它给隐藏掉呢? 第六行下面的第七行ch和第八行sh,是新版本新添加的一对兄弟,也需要一起看: ch s:xx m:xx sh s:xx o:xx m:xx ml:xx 这两行的作用差不多,其用处都是显示玩家当前位置(x和z坐标)最高的特定方块的y坐标信息,区别就在于一个是客户端的信息(client highest)一个是服务端的信息(server highest)。 ch和sh都有s和m这两个参数。s的作用是显示玩家当前所处位置(x和z坐标)最高的非空气方块的方块的y坐标信息。m是显示玩家当前所处位置(x和z坐标)最高的任意液体或会挡住你的方块的y坐标信息。 m这个参数可能会比较难以理解。那就举个例子: 假设一个服务器的腐竹,由于服务器没人玩,很无聊,就用蜘蛛网从地上一直搭(创造模式)搭到y坐标为212的地方。此时如果有一位玩家路过这个服务器,并且从蜘蛛网下面走了过去,那么在穿过蜘蛛网的时候,它的ch一行会显示为: ch s:212,m:64 因为蜘蛛网并不会挡住玩家,它本身也不是个液体,导致并不会被m参数算到。但蜘蛛网并不是个空气方块,s参数便记录了它的坐标,所以最终得出了这个结果。 sh在ch的基础上还有o和ml这两个参数(1.18版本还多了个东西在s和o之间,只不过目前在预览版中显示为null:xx),但这两位并不适合单独介绍,而是应该和刚才那两位,搞一个表格(建议电脑或平板上观看): 参数名\/方块类型——空气方块—挡人方块—液体—树叶—其他 s——————————x————√———√——√——√ o —————————x————√———x——√——x m—————————x————√———√——√——x ml—————————x————√———√——x——x 可能这仍然有些难以理解,但好在,这位腐竹又搞了两个奇怪的塔: 1 蜘蛛网--- 67 水--- 66 树叶--- 65 草方块---64 2 蜘蛛网--- 67 树叶--- 66 水--- 65 草方块--- 64 如果此时有一位管理大大从正上方路过,那么它的调试面板sh这一行将会显示: 1——sh s:67 o:65 m:66 ml:66 (因为蜘蛛网不是空气方块,所以s是67;因为蜘蛛网和水都不会挡住玩家,但树叶可以,所以o是65;因为蜘蛛网和水都不会挡住玩家,但水是液体,所以m和ml都是66) 2——sh s:67 o:66 m:66 ml:65 (因为.....所以s是67;因为树叶会挡住玩家,但蜘蛛网不会,所以o和m都是66;因为蜘蛛网不会挡住玩家,树叶不属于ml的计算范围,水是液体,所以ml是65) 理解了吧?不理解就再看一遍。 第九行和第十行即biome(生物群系)和local difficultly(区域难度)。 第十一行,即sc一行,是在1.16版本中新加入的一行参数,作用是显示生物生成的详细信息: sc:xx——当前可以生成生物的区块数量,似乎与渲染距离没有关系 m:xx——当前所有已生成的生物中,敌对生物的总数量 c:xx——当前所有已生成的生物中,动物的总数量 a:xx——当前所有已生成的生物中,环境生物(比如蝙蝠)的总数量 w:xx——当前所有已生成的生物中,水生动物的总数量 m:xx——当前所有已生成的生物中,其他类型的生物的总数量 最后一行,也就是sounds行: sounds:xx\/xxx + x\/x(mood xx%) sounds一行主要是关于游戏声音。minecraft的游戏声音大致可以分为三类: 普通音效、环境音效、背景音乐 普通音效——游戏中的大部分声音是普通音效,比如放置方块、怪物\/动物发出声音、脚步声等都算普通音效 环境音效——环境音效一般是指在特定场景下播放的声音,说白点就是你在挖矿的时候听到的怪声(晚上玩怪恐怖的)。环境音效除了在洞穴里有,还有在水下和在下界的环境音效。 背景音乐——不用多说,c418的音乐真好听。 加号的左边即是普通音效,具体是: 当前正在播放的普通音效数量\/可以播放的普通音效数量上限 右边是环境音效,只不过此环境音效还包括了唱片机播放的音乐和游戏背景音乐(或者更准确的来讲应该使用英文minecraft wiki的streamed sounds): 当前正在播放的环境音效数量\/可以播放的环境音效数量上限 在这一串参数后面,还有一个: mood xx% 这个东西目前中文wiki上没有说明。作者将这东西放进百度生草机里搅拌了一下,得出来了: 情绪 xx% 生草机出来的东西准不准不知道,但这东西绝对跟你的情绪有关。 这东西的百分比后面有一个算法:mood algorithm mood 算法大致的代码(伪)是这样的: updatemood(mood): tickdy = 6000 maxlightlevel = 15 block = select a random block in a 17x17x17 block cube centered around the yer skylight = block.getskylightlevel  if (skylight > 0): mood = mood -(skylight \/ maxlightlevel)* 0.015 else: blocklight = block.getblocklightlevel  mood = mood -(blocklight - 1)\/ tickdy if (mood ≥ 1.0): yer.yspookysound  mood = 0.0 else if (mood < 0): mood = 0.0 翻译: 声明“更新情绪”方法(情绪): 设定变量“游戏刻延迟”值为6000 设定变量“最大光照等级”值为15 在以玩家为中心的17x17x17的立方体中随机选定一个方块 获取该方块的天空光照等级 如果(天空光照等级大于0) 设定变量“情绪”的值=情绪-(天空光照等级÷ 最大光照等级)x 0.015 否则 获取该方块的方块光照等级 设定变量“情绪”的值=情绪-(方块光照等级- 1)÷游戏刻延迟 如果(情绪大于等于1.0) 执行玩家类方法“游戏里诡异的声音” 设定变量“情绪”的值为0.0 否则如果(情绪小于0) 设定变量“情绪”的值为0.0 为了让你能够真正理解这算法是怎么算的,我们来举个栗子。 假设此时你正在矿洞里挖矿。在上一游戏刻中,你的情绪值为0.(mood 99%),如果此刻游戏随机到了你正前方五格的方块,那么: 游戏通过执行block.getskylightlevel这个方法(java语言中的方法类似于minecraft中的函数,将一串代码包起来成为一个方法,需要执行的时候再调用),获取到了这个方块的天空光照等级为0。 因为这个方块的天空光照等级是0,所以游戏又执行了block.getblocklightlevel这个方法,获取到了这个方块的方块光照等级,发现也是0。 于是游戏做了一个简单的运算: mood = 0.-(0-1)÷6000 =0.-(-1)÷6000 =0.-(-0.000) =0.+0.000 =1.000 此时游戏发现1.000大于1,所以执行了yer.yspookysound方法,然后你就听到了一辆地铁驶过的声音(cave 11)。 但如果这个方块的方块光照等级大于等于1,或者这个方块的天空光照大于0,那么mood值反而会减少一些或不增不减,因为如果仔细观察上面的代码,你会发现计算mood时都是减法,要让mood增加,必须要让减数为负数,各种情况下,只有天空和方块光照等级都为0的情况下才能得出负数。 mood算法每游戏刻都会执行一遍,每次执行最多增加1\/6000。也就是说,在极端的情况下,即你完全置身于黑暗之中,mood也需要每五分钟才能够轮回一次。 说了这么多,那么这个mood xx%到底有什么用? 看一下上面的假设就知道了,当mood到100%也就是你的情绪达到了顶峰时,游戏就会突然给你随机放一个环境音效,把你吓一跳。 嗯.......不愧是mojang,把玩家的情绪拿捏得明明白白的。 到这儿。左边的第二方阵算是彻底研究完了,但本章还没有结束。 1.8.2版本,左边新出现了个第三方阵,这个第三方阵主要是关于调试本身的信息,它长这个样子: (1.14版本之前) debug:pie [shift]:hidden fps [alt]:hidden for help:press f3 + q (1.14版本之后) debug:pie [shift]:hidden fps + tps [alt]:hidden for help:press f3 + q 第一行debug主要是一些关于调试界面的参数。pie指的是饼图,这东西可以通过按shift + f3显示(visible),默认是隐藏(hidden)。 什么?你说按了没用? 哦,这东西得这样按出来: 第一步,按住shift,由于和游戏按键冲突,按住时会蹲下或向下飞行。如果此时调试界面已打开,请先关闭调试界面。 第二步,继续按住shift,同时另一个手指按住f3。 第三步,两个手指同时放开。看,饼图出来了!(这饼图小得字都看不清啊) fps(1.14版本之后还有一个tps,即ticks per second每秒传输刻数)指的是帧(刻)生成时间柱状图,可以按alt + f3显示。在1.14版本之前,这儿只有一个柱状图。这个柱状图有两条参考线,一个参考线在最上面,代表30fps;另一个在中间,代表60fps。这个柱状图的柱子越低,即代表每帧运算的时间越快,fps越高。 在1.13版本之前,这个柱状图很简陋,但相对于之后的版本,多了一个东西: xx mb\/s 作者猜测这可能跟读写速度有关,可能是内存的读写速度。 1.13版本更新后,这个柱状图就好看多了,首先它变大了,其次它有更丰富的颜色了——柱子越矮越绿,越高越红。 1.14版本更新后,这儿又多了个tps的生成时间柱状图,看法和fps的柱子差不多。同时,柱状图上面会显示当前最低和最高计算用时,单位为毫秒。 上面所述的两个附加调试图在关闭调试界面后,如果再打开调试界面,那么将会又一次隐藏。你可能以为我要说如何保持它默认开启,但可惜不是,因为没有这个功能。我要说的是:如何一次性将两个图表都打开。 你只需要按下shift + alt + f3即可。 第二行for help相信大家都看得懂,这就类似于软件中的“获取帮助”,这一行就是提醒你按f3 + q可以了解更多东西。 具体有什么东西如下: [?~]f3 + a:重新加载所有区块 [1.8~]f3 + b:打开或关闭实体的碰撞箱(白色线条)、朝向(蓝色线条)和生物的视线高度(红色线条)信息。 [?~1.13~]f3 + c:短按以\/execute指令的形式复制玩家本身的坐标、旋转角度信息[1.13及之后]: \/execute in minecraft:overworld run tp @s...... 长按10秒以使minecraft游戏本身强制性崩溃 [1.13.1~]ctrl + f3 + c:按住10秒以使java本身强制性崩溃(有些键盘需要使用右ctrl) [?~]f3 + d:清空聊天记录,但仍然可以通过上下键查看之前输入过的指令和消息 [1.9~]f3 + f:使客户端渲染距离+1(范围为2~32) [1.9~]f3 + shift + f:使客户端渲染距离-1(范围为2~32) [1.10~]f3 + g:打开或关闭区块边界(红色,玩家所处区块为黄色)、玩家所处区块区段边界(蓝色)信息 [1.4.2~]f3 + h:打开或关闭高级提示框(即显示物品详细信息,如物品id、nbt标签) [1.13~]f3 + i:将玩家所注视的方块或实体在服务端的信息复制下来,具体如下。 方块:\/setblock 坐标信息,方块id[方块状态] 实体:\/summon 实体id,实体坐标,实体nbt [1.13~]shift + f3 + i:将玩家所注视的方块或实体在客户端的信息复制下来。 [?~1.12.2|1.17~]f3 + l:wiki上说是“生成、保存性能分析数据”。在1.12.2版本,按住f3 +l会显示“正在加载可见区块”,但实际啥也没有发生。 [1.9~1.16~|需要执行\/gamemode权限]f3 + n:在上一个游戏模式和旁观模式切换[1.15之后]在创造模式和旁观模式中切换[1.15及之前] [1.4.2~]f3 + p:开启或关闭当minecraft窗口没被选中时自动暂停的功能 [1.9~]f3 + q:显示帮助列表 [?~1.9]f3 + s:重新加载声音 [?~]f3 + t:重新加载所有资源包(包括原版资源包)和声音 [1.16~|需要执行\/gamemode权限]f3 + f4:在四种模式中切换,可以使用鼠标选择或按f4下一个,松开f3即切换到选定模式 [1.14.1~]f3 + esc:暂停游戏而不显示菜单,多人模式无法暂停 [1.2.4~]shift + f3:显示饼状图 [1.8.2~]alt + f3:显示柱状图 [1.8.2~]shift +alt + f3:我全都要显示 到这里,调试界面左边这一栏才算介绍完成。 本章到此结束。 第189章 打开调试界面,你会发现你的准心出现了三条颜色不一样的线。 这三条线朝向的方向都是xyz的正方向,其中红色的是x轴,蓝色的是z轴,绿色的是y轴。 这可比看facing那一行来判断坐标正负有用多了(mojang啊你为什么一定要用positive和negative啊,用+和-难道不香吗?) 前三章的研究主要是针对左侧一栏,不难发现左侧一栏更多是关于游戏的信息。接下来我们要研究右侧一栏,这个右侧一栏主要是关于客户端的硬件信息,毕竟硬件决定了软件的上限嘛。 在1.8版本,右侧一共有两个方阵。第一个方阵主要是关于游戏的java版本和内存使用情况: java:1.xx.x_xx 32bit\/64bit——显示java的版本号和位数 mem:xx%当前占用内存\/占用内存上限mb——显示当前内存占用内存最大值的百分比,以及具体占用的内存量\/设定占用内存的最大值。 allocated:xx%已分配内存——已分配给游戏的内存相对于内存上限的百分比和具体的值 这里顺带讲一下,什么是内存以及内存和硬盘的区别。 但凡是个计算机,肯定有不止一个存储装置。此时你估计会问:为什么说不止一个呢?存储装置不就是硬盘或sd卡吗? nonono,存储装置不只是指硬盘和sd卡,这两个东西只是存储装置的一大类,特点是读写速度快、断电不会丢失数据、保存时间长、容量大,主要作用是存储各种各样的资料,比如系统资料,软件数据、你的学习资料等。总之,硬盘和sd卡就相当于计算机的长期记忆。 另一大类则是内存(民间里也称“运存”)。内存也是每个计算机必须要有的,所以一个计算机不止有一个存储装置(况且还有显存和cpu缓存呢)。内存有如下特点: 1读写速度特快,比硬盘快不知道多少倍 2使用电力存储,一停电立马gg 3容量一般相对于硬盘来说很小 内存最主要的用途是存放程序在运行时产生的临时数据。一个程序想要运行,必须要先将要运行的东西从硬盘读取出来存到内存中,然后再经cpu缓存给cpu运行(cpu缓存是cpu和内存数据交换的过渡区,一般有三个区,分别是l1、l2和l3。cpu缓存虽然容量极小,但读写速度超级快,比内存都要快许多)。如果这个软件被关闭,那么关于这个软件的内存数据将会被清除。 这就是为什么当你的老师上完课后,在没有关闭ppt的情况下直接把u盘拔出带走ppt还能正常播放甚至另存为的原因,因为软件在运行该文件时,已经把这个文件从u盘拷贝到内存里了。 游戏对内存的使用也是一样的。如果你在minecraft中运行太多的指令、放太多的实体、一下子改变太多的方块、加太多的模组以及使用太高清的材质包时,都会占用大量内存。 (所以,以后如果再看到那种超高清材质包的视频,千万别只组团偷显卡,内存也要偷,不然游戏还没进去就“:(你的电脑遇到问题,需要重新启动。我们只收集某些错误信息,然后为你重新启动。(完成 0%)”) 也就是说,内存就相当于计算机的短期记忆。 但或许你还不懂已分配内存、当前占用内存和设定占用内存最大值的区别。已分配内存就是计算机分配给程序的内存空间大小,这个大小是动态变化的,具体是由该程序实际占用内存大小来决定。而占用内存大小的上限则是程序给自己设定的一个内存占用限度,并不等于计算机实际分配给程序的内存空间大小。 接下来我们来看看第二个方阵,这个方阵主要是关于你的显卡、显示屏信息: disy:aaaaxbbbb (显卡品牌名称)——即你的minecraft窗口分辨率和显卡品牌 显卡名称,显卡支持的东西 显卡驱动程序版本 minecraft java1.8版本到1.12.2版本期间,新更新了一个cpu方阵将disy这一方阵挤到了第三去。这个cpu方阵在1.12.2版本时长这样: native:xxx\/xxxxmb——java虚拟机目前使用内存和虚拟机内存使用上限 cpu:核心数,品牌和型号,运行速度(ghz) native这一行作者在写作时还在,隔了几天再次打开不知怎么就没掉了。关于native内存和java虚拟机的更多内容作者这边就不细讲了,去csdn有一篇文章叫《java native内存_jvm heap memory和native memory》(作者是“海阔山高人为峰”)那里或上搜索引擎了解。 到这儿,右侧一行也算是基本结束了....... 真的结束了吗? 现在,请你看向任何一个非气态方块。在1.13版本之前,如果你看到了固态方块,那右侧一栏就会显示关于这个方块的信息: 命名空间:方块id 方块状态:状态值 方块状态:状态值 其中,第一行的方块名绝对会显示,第二行开始就是该方块的方块状态。 什么是方块状态?在之前的章节中我们已经见到过很多次,但大多数时候都是一笔带过。由于接下来一两卷就要开始详细了解方块,这儿就先简单了解一下。 方块状态,正如其名,就是方块本身所处的状态,是进一步定义一个方块的附加数据。朝向就是最常见的方块状态之一。 如果你准心瞄准到了草方块,就会显示这些信息: minecraft:grass snowy:false 其中,snowy:false就是这个方块的方块状态。 snowy状态的值是个布尔值,当值为true时草方块就会变成“雪方块”。 有一些常见的方块状态,知道这些不光是在指令方面有大用,甚至在生存、红石方面都有许多用处: facing——朝向,接受north(北)、south(南)、east(东)、west(西)、up(上)、down(下) level——有不同意思,接受数值。为液体时作为液体方块扩撒的等级,每扩散一次-1,直到为0。为堆肥桶和炼药锅时作为填积的厚度等级。 age和stage——一般作为植物或方块的生长状态或等级,大部分方块的该状态会在随机刻后增加。如马铃薯的age就接受0到7,0~1、2~3、4~6和7分别为四个生长阶段。 在1.13版本之后,mojang加入了查看液体方块信息的功能,这一部分就发生了大改动,变成这个样子: targeted block 命名空间:方块id 该方块的方块状态(方块状态:值) 该方块的方块标签(#命名空间:标签名) targeted fluid 命名空间:液体方块id 该液体的方块状态(方块状态:值) 该液体的方块标签(#命名空间:标签名) 不难发现,在1.13及以上版本多了方块标签。什么是方块标签?这和我们的记分板标签(tag)差不多,都是通过给特定的实体、方块赋予特定标签,以使特定时候能调用。但方块标签和记分板标签有一点不同——前者是默认就存在的,后者需要手动添加。 比如我们的草方块,如果在1.13.2版本中看向它,那么将会显示: targeted block minecraft:grass_block snowy:false #minecraft:enderman_holdable #minecraft:valid_spawn 具有enderman_holdable标签的方块可以被末影人拿起,你看向西瓜也会发现其具有该标签。 具有valid_spawn标签的方块即是玩家的有效出生位置(?)。 在前两章中,我们曾发现looking at一行在1.16版本中没掉了。那么looking at的信息去哪了呢? 和右侧的targeted block、targeted fluid合并变成了: targeted block:x,y,z ........ targeted fluid:x,y,z ........ 到这儿,我们整个调试界面也算是讲完了,本章也算结束了。 (唉作者,你咋隔了快一个月才更新了呢?) (哦,原因是因为最近在对前面的章节大修,你此时如果去翻前面的内容,会发现从序言开始一直到第三十九章大部分章节都有大改。目前的目标是修到第九十章,可能至少还要再修一个月吧,毕竟一年半过去minecraft更新的内容还是蛮多的) (对了,修改后的章节增加了许多指令的例子,其中不妨有及其有用的指令哦!) 第一百五十二章 调试棒和其他的一些关于调试的东西 在一些mod里,你可能会发现一种可以用来快捷调整方块的工具。在ic2(工业时代2)中,这个工具叫做扳手(注意不是“扳手(新)”和“电动扳手”);在openblock中,这个工具叫做“大金属棒”;那在原版当中,这个工具是什么呢? 一个附了魔的木棍。 没错,真的是这样。这个东西的名字叫做“调试棒”,仅java版所有,是mojang官方提供的“扳手”,用途很简单,右键用来调整方块的朝向、状态,左键确定调整该方块的状态为此值(对于可以交互的方块,需要潜行才能使用调试棒)。 那么该怎么获得这个神奇的东西呢? 首先,这个东西你是不能通过附魔木棍获得的,木棍也不是个工具。其次,调试棒不可以被合成,你在创造模式下的背包中也找不到这个东西。第三,它是不会自然生成在某个宝箱中的(除非你专门搞了个可以生成这个东西的战利品表)。这个调试棒,它有它专属的id:minecraft:debug_stick,所以你可以也仅能通过\/give @s minecraft:debug_stick获得这个神奇的东西。 调试棒为什么只能通过指令获得,而不像那些mod中的扳手一样可以直接合成? 因为调试棒稍微比那些东西要高级那么亿丢丢。哪亿丢丢呢?调试棒改变的是方块的方块状态,而不仅仅是方块的朝向之类的显而易见的东西,且它并没有耐久。 什么是方块状态?如果你是在8月前就看过第三十章的读者,那么你估计不知道这东西是个啥玩意,建议先回去看一下。 因为可以改变这个方块状态,导致玩家们可以利用这个东西作弊。当然,mojang官方也早就料到玩家会用这个东西作弊,所以特地添加了一个使用限制:生存、冒险模式下不可用。 调试棒这东西在没有安mod和测试mod的情况下是及其好用的。它可以用于建筑、红石等方面,省得拆方块并调整好你的视角再放置。至于指令方面,好像没多大用处。 历史 java 1.13——加入了调试棒。 1.16——由于火现在有判定箱,现在使用调试棒可以更改火的方块状态。 关于调试的东西,除了调试棒,还有一个藏得及其深的模式:调试模式。 调试模式的开启需要你在创建世界过程中,按住alt键并一直点击世界类型选项,此时调试模式就会出现。选择它并创建,你就会进入到一个所有方块排列得整整齐齐的世界。这个模式主要是用于mod开发过程中测试方块所用,平常我们用不到,这里也就不细讲了,自己去wiki上了解。 历史 java 1.8——加入了调试模式 1.9——方块现在会在改变状态时复原,并修复了门和活版门碰撞箱异常的问题 关于调试,还有两条指令,前者主要是给那些开发人员使用的,后者我们普通玩家有时候可能要用到: \/debug 作用:生成游戏调试(和游戏性能检测[该功能现已移除])数据,并以txt文件的形式保存于“.minecraft\/debug\/” 需要权限等级:3 版本独占:仅java版 需要作弊:否 指令格式: \/debug start——开始调试会话 \/debug stop——结束调试会话,并输出结果文件 \/debug function ——测试函数 \/debug report——在调试过程中输出当前世界的信息并压缩成一个zip文件,用于获取更详细的信息(于java1.17中移除) \/debug chunk [坐标]——此指令的具体描述minecraft wiki上没有记载,初步猜测应该是保存坐标所处的区块(于java1.13前某版本被移除) 历史 java 1.3.1——加入了\/debug 1.8——\/debug现在可在单人模式中运行,并且加入了\/debug chunk ?——移除了\/debug chunk 1.14.4——加入了\/debug report 1.17——加入了\/debug function,同时因为f3+l和\/perf的出现移除了\/debug report \/perf 作用:检测游戏性能并记录数据 需要权限等级:4 版本独占:仅java版 需要作弊:否 指令格式: \/perf start——开始一段长达10秒的性能测试,并将记录压缩存储于“.minecraft\/debug\/profiling\/.zip” \/perf stop——提前结束性能测试 历史 1.17——加入了\/perf 第一百五十三章 详细了解村庄更新之前的村民 (本章的内容全部都是村庄更新之前的游戏内容,即java1.14、基岩版1.11和ystation 4版1.91之前,有少数内容仍适用于村庄更新后) 在之前的章节中,我们似乎了解了一大堆好像没啥用的内容。但没关系,因为接下来我们将会了解村民和基岩版新出的npc,利用他们更好地建设地图和服务器。 在学习如何自定义村民交易之前,我们得先详细了解一遍村民。 村民(minecraft:viger),是一个早在minecraft java 1.0版本就出现的被动型生物,最开始被称为“testificate”(测试版生物),并拥有5大职业。 村民有20点生命值。成年村民高195cm(1.95方块),宽60cm(0.6方块);幼年村民高97.5cm(0.975方块),宽30cm(0.3方块)。 有五种耳熟能详的途径可以生成村民:1村庄结构生成2治愈僵尸村民3村民的繁殖4指令生成5村民刷怪蛋 村民在白天会到处闲逛,走街串巷,与其他村民相遇时会互相盯着(这就是村民的社交行为,搁这儿目光传递信息呢)。有时会到屋子里,有时会到屋子外,如果有很多个村民同时挤在一个门口还会导致门一直开关,结果谁也进不去,谁也出不来,还发出了极大的噪声。如果村民闲逛过头,跑出了村庄,他将会赶紧回去。如果回不去,并且在村庄32格开外的话,他将会在6秒内忘记该村庄并在32格范围内寻找新的村庄。 当村民脚下有掉落的农作物,并且周围没有玩家和漏斗拾取这些农作物时,他将会以一种比老年人还慢的速度捡起这些东西。村民实际上具有一个8格的背包,但仅可存放食物和种子。村民会将小麦合成为面包,并将食物分享给那些几乎没有食物的村民。村民也有盔甲栏,只不过穿上盔甲并不会显示(仍然会有效果,比如你给村民戴上一个荆棘的头盔,这个村民几乎就无敌了)。 褐色长袍的村民(不管二级职业是什么,统一叫做农民),在身上的食物不足的情况下,他会去收割田地以获取食物(不管这个村民是否成年)。当农民身上有种子的情况下,他会尝试耕种这个种子于附近的田地。 玩家如果和村民靠得过近,除了是在逃命或回家,其他情况下村民都会试图与玩家进行目光交流(基岩版中村民不会停下)。如果玩家敲了村民,他们会像其他大多数被动型生物一样逃窜(除了原主机版中的村民),并会惊动铁傀儡。 村民在晚上和下雨时会呆在房子里,并关上大门,直到早晨出来。如果村民遇见僵尸、灾厄村民、溺尸或恼鬼,那么他将会直接逃离,敌对生物也会去追赶村民直到村民死亡或村民逃离到视线外(村民看到僵尸猪人也会跑,虽然僵尸猪人并不会攻击村民,估计是因为村民对僵尸种类的生物有ptsd)。如果村民被僵尸打死,会有几率转化为僵尸村民,这个几率会随难度提升(简单:0%|普通:50%|困难:100%)。 幼年村民有时候会在一起玩抓人游戏,闲的时候会跑来跑去。如果他们遇见了铁傀儡,可能会好奇地打探着它,并且如果铁傀儡拿着虞美人,幼年村民还会小心翼翼地从铁傀儡手上接过虞美人。 村民的繁殖和其他的可繁殖生物大不相同。他们如果要繁殖必须要达成以下条件: 1.至少有两个同村庄的村民并拥有充足的食物 2.当前村庄的成年村民数量并没有达到该村庄有效门数量的135%[java版]或200%[基岩版] 3.村民有繁殖意愿(这有很大几率会在玩家与村民交易后出现) (有效门指的是一扇木门,注意是木门,在门的两侧5格的范围中外部空间方块的数量不一致,才可以算作有效门。外部空间方块指的是上面被不透明方块遮住的方块。总之,你正常造一个房子,这个门就会被判定为有效门。) 村民的主要作用,就是交易。 村民的五大职业,具体是农民(褐色)、图书管理员(白色)、牧师(粉色,注意虽然是粉色但人家可不是女的)、铁匠(褐色+黑色)和屠夫(褐色+白色),每种职业都还有细分的二级职业,如农民职业就细分为农民、渔夫、牧羊人和制箭师。一级职业的判断可以直接从村民的衣着上区分,而二级职业需要打开交易界面才可以看到。 玩家和不同职业的村民进行交易,就可以用不同的物品换取绿宝石或用绿宝石换取不同的物品。只不过换取的数量和和需要的物品数量是随机的,这就导致有些村民很坑,有些村民相对来说比较良心(良心也良心不到哪里去)。这就是为什么村民被称为奸商并且大家都热衷于搞村民的原因。然而,将奸商搞死并不会获得什么神奇的东西,连经验值都没有。反而你照着奸商的意愿去买东西,你还可以获得3~6点经验值甚至是8~11点经验值(村民想繁殖时与村民交易就会这样)。 村民的交易项目具有等级划分,更高等级的交易项目需要完成前一等级的交易才可以开启。每个交易项目都有交易次数限制,这就导致你不能将村民作为atm机。当达到交易次数限制时,你就必须和村民交易他新开启的项目(村民新开一个交易项目时,他会获得生命恢复的效果),再等待一段时间。当村民发出绿色粒子之后,所有交易项目将会重新开放。 还有一种身着绿色衣服的村民,这种村民我们亲切地称呼他们为“傻子”。真的,真就叫“傻子”,官方真就这么叫的。 傻子村民是个名副其实的傻子,他和其他村民最大的不同是不会售卖东西,但其他方面(繁殖和行为)都与有职业的村民无异。 村民变为僵尸村民后,职业并不会消失,但如果你使用虚弱药水+金苹果重新治疗村民,转化完成后该村民的职业将随机变化,并刷新交易(这个机制就导致我们需要某个职业的村民但找不到时,就算找到一个符合我们需求的僵尸村民,治疗后还要看我们的运气)。 以上内容就是村民在村庄更新前的习性。下一章我们将会开始学习如何自定义村民交易。 历史 java 1.0.0——加入了村民(viger),并赋予村民猪一般的脑子(猪的ai)。在beta 1.9-pre2之前,村民被称为“testificate”(测试版生物)。此时的村民已经具有五大职业。 1.1——为创造模式加入了村民刷怪蛋,但只能生成农民。 1.2.1——村民现在具有开关门、判断房屋的能力,并且会根据有效门的数量进行繁殖。村民此时也会与其他被动生物互动,僵尸此时开始与村民敌对。幼年村民现在可以疾跑。 1.3.1——刷怪蛋召唤的村民现在具有随机职业,并为村民加入了交易系统。此时的村民会在某一职业过少时转化为该职业,并且当时的交易项目在交易次数达到上限后会被移除。 1.4.2——村民现在会对玩家的行为做出正面和负面的反应,并加入了僵尸村民。交易项目也不再会被移除了。 1.4.4——现在手持村民刷怪蛋同时右键村民可以生出幼年村民 1.6.1——为村民加入了各种音效 1.8——加入了二级职业,并重写了交易系统,几乎变成了本章所述的那样,并为村民添加了可以控制交易成功获得的经验值的nbt标签。村民此时繁殖需要具有意愿。普通村民被移除,但纹理仍然可以在游戏文件夹中找到。职业id超过4时会重复1~4的职业id。村民现在遭遇闪电会变成女巫。农民(一级职业)现在可以收获成熟的农作物。 1.8.1——村民现在不会忽视nbt数据和损害值。 1.9——农民现在懂得如何种植、收获并捡起甜菜根。同时,村民的身高从180cm变成了195cm(幼年村民从90cm到97.5cm)。现在可在雪屋找到被困的牧师村民。 1.11——加入了傻子村民,并将村民的实体id从minecraft:viger改为minecraft:viger。同时,添加了“制图师”二级职业。村民现在的交易可以从战利品表中抽取。 1.13——将武器商和工具商的职业id交换(武器商3→2,工具商2→3),村民现在会避开溺尸了。 2018年9月29日——村庄更新被透露。接下来的内容就是之后几章要了解的了。 携带版和基岩版 -携带版alpha- 0.9.0——加入了具有猪脑的村民和其音效,此时的村民和僵尸已经敌对,幼年村民此时就会疾跑了。 0.12.1——村民现在会繁殖、开关橡木门、晚上回家、转化为僵尸村民、收获并种植农作物和对玩家产生积极和消极的意见。 0.13.0——村民现在会开关所有类型的木门。 0.14.0——村民现在被雷劈会变成女巫,并调高了村民的身高。 0.15.0——村民现在会怕尸壳 -携带版- 1.0.0——村民现在会生成在雪屋地下室 1.0.4——加入了交易系统、傻子村民(并不可以自然生成)、头和成年人一样大的幼年村民,村民此时会分享食物,并只在有意愿时才繁衍。 1.1.0——村民现在会远离灾厄村民和恼鬼,并为村民加入了“制图师”二级职业。 -基岩版- 1.4.0——村民现在会远离溺尸 1.9.0——村民现在会远离掠夺者 1.10.0——村庄与掠夺更新 第一百五十四章 村庄与掠夺更新前的自定义交易 林地府邸和海底神殿这两个遗迹,一般都生成在几千格远的地方,如果想要单独靠运气寻找那简直是大海捞针。如果有作弊的话用\/locate也就罢了,没开作弊或者是在服务器内找,那就必须得找到身着白色服装的制图师换取林地探险家地图和海洋探险家地图。 现在,你找到了一个制图师村民,他希望能用1颗绿宝石换取你的36张纸。你早有准备,与村民进行了一场交易,并获得了些许经验值。村民看起来很高兴,头上冒出绿色的粒子并伴随生命提升效果给你开了一个新的交易项目:用一个指南针换取一颗绿宝石。 为了不死图腾,你又向村民换取了一颗绿宝石。村民更加开心了,继续给你开了一个新的交易........最终,你成功用44颗绿宝石加上两个指南针换取了那两张你梦寐以求的地图。 后来,其他玩家也发现了这个制图师。其中一个玩家携带了大量纸张,将这个村民的第一个交易项目换没了。但当他与该村民进行其他交易项目时,那个没货的交易项目又有货了。 如你所见,村民的交易系统有以下几个特点: 1指定的村民职业具有指定的交易项目 2交易项目会逐步开放,直到没有项目可开放为止 3一个交易项目可以用一到两种物品换取指定的物品。 4交易项目使用后可以获得一些经验 5交易项目具有次数限制,次数限制达到后将无法使用该交易项目,需要与村民进行其他交易后才会重新开放。 上面这几个特点分别对应村民nbt标签中的: 1profession和career(均为int整形) 2——careerlevel(int整形) 3——一个交易项目中的buy、bugb和sell(均为复合标签) 4——一个交易项目中的rewardexp(byte布尔值) 5——一个交易项目中的maxuses(int整形) 为了能够用nbt自定义村民交易,我们首先需要注意的是profession和career标签,这两个nbt标签的作用分别是: profession——确定村民的一级职业,即村民的衣服是什么颜色。0为棕色(农民),1为白色(图书管理员),2为紫色(牧师),3为棕色+黑色(铁匠),4为棕色+白色(屠夫)5为绿色(傻子)。如果不填该项游戏会随机赋予村民一级职业。 career——确定村民的二级职业,即村民的具体职业。如果没有这项或这项为0,当玩家打开该村民的交易菜单时游戏将会刷新该村民的职业并重置careerlevel为1。如果不填该项游戏会随机赋予村民二级职业。 村民的二级职业id具体如下: ?棕色长袍(农民)——1为农民,2为渔夫,3为牧羊人,4为制箭师; 1白色长袍(图书管理员)——1为图书管理员,2为制箭师; 2紫色长袍(牧师)——1为牧师; 3棕色+黑色(铁匠)——1为盔甲商,2为工具商,3为武器商; 4棕色+白色(屠夫)——1为屠夫,2为皮匠; 5蓝色长袍(傻子)——1为傻子。 需要注意,在java1.13版本中,工具商和武器商的id进行了交换。也就是在1.13版本中铁匠下面的二级职业id变为了“1为盔甲商,2为武器商,3为工具商”。 举个很简单的例子: \/summon minecraft:viger ~~~{profession:0,career:1} 这条指令将会生成一名普普通通的农民。 careerlevel直译为“交易水平”。它的作用很简单,就是控制村民开放的交易项目的多少,基本上就相当于村庄更新后的“新手”、“老手”、“大师”各种村民级别,每当完成一次交易就刷新并增加一些。和career标签一样,如果为0就会重新刷新该村民的职业将careerlevel设为1。 举个简单的例子,假设有一个农民,游戏给他的交易项目有: 2绿宝石→1西瓜(careerlevel为1开启) 1闪烁的瓜皮→1绿宝石(careerlevel为2开启) 1闪烁的西瓜→1绿宝石(careerlevel为2开启) 10绿宝石→1大鹏(careerlevel为4开启) 1水果摊+1绿宝石→1生瓜蛋子(careerlevel为6开启) 2猹→1绿宝石(careerlevel为10开启) 1秤→5绿宝石(careerlevel为12开启) 1指南针+15西瓜→30绿宝石(careerlevel为13开启) 1萨日朗花+10绿宝石→1章鱼哥(careerlevel为17开启) 此时有一个叫“liu_huaqiang”的玩家骑着heat and climate(热量与气候)模组中的摩托车(黑)前来买瓜。首先他换取了一个西瓜,使该村民的careerlevel提升到了2,开放了两个新的交易项目。随后他用闪烁的瓜皮和闪烁的西瓜兑换了2颗绿宝石,进一步使村民的该标签提升到了4,又开放了1个交易。就这样,最终当careerlevel≥17时,村民才不再开放新的交易项目。 (然后这名玩家来了个跳劈将村民一刀砍死了) careerlevel标签对于自定义交易很重要。如果它的值过低,没有超过该职业最后开放的交易项目需要的careerlevel的值,玩家在进行自定义的交易项目后村民将会开放新的交易项目。 比如某服务器腐竹使用了上面那名卖瓜的村民作为自定义村民的职业,但在编辑自定义交易项目时忘记了将careerlevel设为大于或等于17的值。这就导致玩家前来与该村民进行交易后,村民又开放了两个新的交易项目,使玩家们很疑惑。 上面这些都是自定义交易相关联的内容,而接下来我们将要学***内容:offers标签。 自定义交易最重要的nbt标签就是offers(复合标签)和recipes(列表)。具体的格式如下: {offers:{recipes:[{一个交易项目},{一个交易项目}]}} offers有什么用我们并不知道,似乎去掉这个nbt标签把recipes拿出来也丝毫没有问题,也不知道mojang为何要在recipes外套一个offers。 单个交易项目有以下nbt标签: rewardexp(byte布尔值)——交易成功后是否提供经验球,1为提供,0为不提供。 maxuses(int整形)——该交易项目能够使用的次数,当交易项目被刷新时会随机增加2~12。 uses(int整形)——该交易项目已经被使用的次数。如果大于等于maxuses该交易项目将会无法使用。交易项目刷新时maxuses会随机增加,uses就再次小于maxuses,交易项目便重新开启。 buy(复合标签)——该交易项目中村民需要收购的东西,值为物品通用标签。 buyb(复合标签)——该交易项目中村民需要收购的第二个东西,值为物品通用标签。该标签不一定需要。 sell(复合标签)——该交易项目中村民出售的东西,值为物品通用标签。 举个简单的例子: \/summon viger ~~~{careerlevel:200,offers:{recipes:[{rewardexp:1,maxuses:,buy:{count:1,id:“twilightforest:trophy“,damage:4},buyb:{count:10,id:“minecraft:emerald“},sell:{count:1,id:“minecraft:diamond_sword“,tag:{ench:[{id:16,lvl:10}]}}}]}} (上面这条指令适用于java1.13之前的版本) 看起来这个很复杂,但如果你能够把它展开再看就极为简单了。 这条指令将会生成一名careerlevel为200的村民,他有一个可以使用15万次并且可以提供经验值的交易项目:用1个幻影骑士战利品(暮色森林mod)+10绿宝石换取一把锋利x的钻石剑。 现在你可以尝试自己去自定义一个交易项目。但请注意,最好新建一个txt文件并使用notepad、文本文档之类的程序打开再在里面编写指令(因为这样子可以用换行+tab键以类似于代码的样子编写,极为方便),编写完成后再复制进游戏中执行。不要在游戏内的命令方块、聊天栏内编写,因为这样子很容易出错! 村民的nbt除了上面讲到和交易有关的标签,还有另外三个并不怎么重要的标签: riches(int整形)——直译为“富有的”,游戏内没有使用,会随村民收到绿宝石而上升。 willing(byte布尔值)——村民是否愿意繁殖,1为愿意。会在进行一次让交易项目刷新的交易后变为1。 inventory(列表)——村民的背包,但并没有栏位之分。举个简单的例子: \/summon viger ~~~{inventory:[{id:“minecraft:emerald“,count:64}]} 这将会生成一名有64个绿宝石的村民。 村民的背包只有8格,所以如果这个列表内的项目超过了8格,多余的部分将会被清除(除非能够与没有超过的部分堆叠)。 现在,你知道如何自定义村民交易了吧?需要注意,单个村民具有的交易项目最多只能有16项! 虎年快乐! 没想到啊,时间过得这么快,转眼间已经两年过去了。 刚开始写本书时我基本保持着一天更两章,但后来由于各种原因频率越来越慢。本书从序言到第五十六章除了两章“mc新手要学习的基础”,其他均是2020年1月内完成的,可以发现我当时有多高产(只不过现在看来那时候写的质量太低了)。当年2月完成了57章~84章,3月完成了85章~94章,4月到2020年末只完成了95~139章。至于2021年全年嘛.......平均一下也就一个月更一章多一点。 到现在(2022年2月1日),把这一章排除在外,本书已经持续断更了3个月26天,断更时间之长甚至连起点上都把我这本书给屏蔽了(搜索不到).......但是我在这三个月多的时间并不是没有更新,实际上这三个月以来我完成了对本书从序言到第五十五章的大修,有很多章节我都重写了一遍,总共修改的字数接近10万字。现在你再去前面翻一翻,会发现有许多地方都焕然一新。 目前我还在继续翻修中,对于写新章节一事已经无暇顾及了。就算现在是寒假,我最多每天也只能翻修3章,一般只能翻修两章,还是几乎重新写的那种。这种翻修可能要持续到今年暑假(因为学业也很紧张),目前仅仅才完成一半的工作量,还要翻修剩下从56章到113章的内容。 总之,在短期内继续将本书写下去已经是不可能的了。 收回一下思绪。今年的春望照样很无聊(神女劈观竟然没卷上去?![滑稽]),今年的bilibili拜年祭做得比去年要好多了。 现在距离跨年仅不到5分钟了,我就在这里祝大家虎年吉祥,新春快乐! 即使接下来可能还要断更几个月,但本书的质量将会比先前的初版要好多了! 新年快乐! 第一百五十五章 村庄与掠夺更新后的村民 minecraft java1.14版本更新,即大名鼎鼎的『村庄与掠夺更新』,对『村民』这个minecraft中非常重要的一个生物进行了大修改,几乎是相当于重写了一遍。 那么村庄与掠夺更新后的村民,相比更新前的村民,有何变化呢? 由于改动实在是太大,本章我们就挑一些重要的内容来讲。至于一那些没讲到的,可以自行前往minecraft wiki了解,或者你直接打开minecraft不就行了。 第一个重大的改动,就是村民更忙了。 在更新前,村民白天如果没跟玩家交易,将会仅仅干两件事情:到处闲逛、与别的村民进行社交活动。对于农民类别的村民来说,也仅仅多出了一项『种地』的活动。但在更新后,我们的村民立马就勤奋了起来。 对于傻子以及失业的村民来说,他们白天仍然只能到处闲逛,以及与其他村民交谈——这也很正常,难不成这些村民还会去打劫玩家啊? 但对于有职业的村民来说,他们白天就有一个更加重要的事情:工作。 村庄于掠夺中一个重要的更新就是为村民添加了『工作站』。什么是工作站呢?工作站就是村民工作的地方,它一般是一个有功能的方块,如炼药锅、制图台。一个有职业的村民大概率会有一个他自己的工作站,一个工作站只能和一个村民绑定。如果一个有职业的村民的工作站没了,对应的村民也将会丢掉工作,变成失业村民。但有一种情况例外:如果对应的村民曾经和玩家交过易,那么该村民将会保留职业,只不过没有工作的地方了而已。 白天,有职业并且绑定了工作站的村民将会来到他们的工作站进行工作(所谓的工作实际上就是村民的眼睛一直盯着那工作站发呆)。和我们一样,村民也会在中午进行休息,也就是到处逛逛,与其他村民聊聊八卦。 说到八卦,那就不得不提一下第二个重大的改动:村民会聊天了。 在村庄与掠夺更新前,村民的社交活动很简单:大眼瞪小眼,有时会更进一步向对方扔点食物,然后也就没了。更新后,mojang给村民添加了一个新的机制:言论,来丰富村民的社交活动。 什么是『言论』呢?举个简单的例子: 张三和李四两位农民是好朋友,他们都住在一个坐落于针叶林的小村庄中。某天,一位玩家来到此村庄寻找制图师,想要获得林地府邸的地图。刚好,张三的邻居王五就是一位制图师。王五和玩家交易得十分顺利,这让王五十分开心,对这位玩家产生了极大的好感。玩家走后,王五遇到了刚刚下班的张三,两人交谈甚欢,顺带也谈到了那名十分友好的玩家。张三听了王五的言论后,也十分高兴。 后来,张三在村里与其他村民交谈时,发现这名玩家也与其他村民进行了许多项的交易。这些正面言论让张三对这名玩家的好感度越来越高。又是一天下班回家,张三遇见了好朋友李四,就顺带告诉了李四这名十分友善的玩家,这让李四也对该玩家生出了好感........ 几天之后,这位玩家的名字传遍了整个村庄,简直是无人不知,无人不晓。大家都对商品进行了打折,并盼望着这名玩家何时能够再来一趟。 村民们确实盼到了这名玩家的再次到来,但带来的并不是他们所想要的交易,而是....... 当王五看见赵六化作一阵白雾散去之时,他感觉到自己的世界观被颠覆了——这位看起来十分友善的玩家,竟然一言不合就干掉了一位村民。那位玩家很快就又离开了,但王五仍然对此印象深刻,并把这件事告诉了其他村民。慢慢地,整个村庄对这名玩家的口碑由正转负,价格也上涨了很多。 (所以这跟张三和李四是好朋友有何关系?) 在上面的例子中,不难发现,村民会通过聊天来传播一些关于玩家的言论,这些信息会影响到村民对玩家的评价,进而影响到村民标的价格。 一条言论包含有三个信息:言论的类别(type)、言论的目标玩家(target)以及言论的强度(value)。言论的类别一共有五种: minor_positive(治疗僵尸村民) major_positive(治疗僵尸村民) minor_negative(攻击村民) major_negative(村民死亡) trading(交易) 当玩家治疗僵尸村民后,被治疗的村民会产生minor_positive和major_positive两种言论。当玩家攻击村民时,被攻击的村民以及附近的村民将会产生minor_negative言论。当玩家击杀村民时,附近的村民会收到major_negative言论。 不同的言论类型会对村民与玩家的好感度造成不同的影响。major_positive(治疗村民)可以使村民对目标玩家的好感度+5,minor_positive(治疗村民)和trading(交易)会让好感度+1,minor_negative(攻击村民)会使好感度-1,major_negative(村民死亡)会使好感度-5。 但好感度并不会影响到村民给出的价格,言论的强度才会。什么是言论强度呢? 看看上面的例子:『玩家走后,王五遇到了刚刚下班的张三,两人交谈甚欢,顺带也谈到了那名十分友好的玩家。张三听了王五的言论后,也十分高兴。 后来,张三在村里与其他村民交谈时,发现这名玩家也与其他村民进行了许多项的交易。这些正面言论让张三对这名玩家的好感度越来越高。』。 虽然这里写的是『好感度越来越高』,但其实这里仅仅是为了方便表述才这么写的,实际上应该是『言论强度越来越高』。 言论强度代表着这个言论在村民脑海中根深蒂固的程度,进而影响到村民给出的价格。言论强度会受到言论类型、时间、玩家以及其他村民的影响。 首先,不同的言论类型所规定的强度基础值和最大值都有所不同,具体如下: 类型|基础值|衰减值|最大值 minor_positive|25|1|200 major_positive|20|0|100 minor_negative|25|20|200 major_negative|25|10|100 trading|2|2|25 其次,言论强度也会慢慢地随着时间衰减,具体是每20分钟,也就是一游戏日衰减一次。不同类型的言论衰减的值也不一样,具体可以看上表。 玩家的行为也会影响到一条言论的强度。再次看看上面的例子:『王五和玩家交易得十分顺利,这让王五十分开心,对这位玩家产生了极大的好感。』 你应该知道,要在制图师处获得林地府邸的地图,得先和村民交易一些其他的项目,最后村民才会开放林地府邸地图的交易。也就是说,这名玩家和王五进行了多次交易,最终大大提高了王五对这名玩家的交易言论强度。 因此我们可以得知:当玩家多次与一个村民重复做相同的事情时,会提高村民指定言论的强度。 最后,其他村民也会影响到言论的强度。我们还是可以看看上面的例子:『后来,张三在村里与其他村民交谈时,发现这名玩家也与其他村民进行了许多项的交易。这些正面言论让张三对这名玩家的好感度越来越高。又是一天下班回家,张三遇见了好朋友李四,就顺带告诉了李四这名十分友善的玩家,这让李四也对该玩家生出了好感』 张三从其他村民处得知了对这名玩家类似的言论,最终也是大大提高了言论强度。所以我们也可以得知:当村民将言论传播给其他村民的时候,如果那位村民已经有了这个言论,就会提高那位村民相应言论的强度。 需要注意的是,当一位村民给其他村民传播言论时,也会降低其自身的言论强度。降低的值因言论类型而异,具体如下: minor_positive|5 major_positive|0 minor_negative|5 major_negative|10 trading|20 并且,不同类型的言论也有不同的传播门槛。言论强度要到达传播门槛,村民才会传播言论给其他村民: minor_positive|5 major_positive|100 minor_negative|20 major_negative|10 trading|20 这村民社会学还真有点复杂,看来要研究村民们的八卦还是有点难度的。但对于玩家也就是我们来说,最关心的其实应该是言论强度对商品价格的影响。 村民受且仅受言论影响的价格可以通过下面的公式进行计算,其中作者自己定义的六角括号〔〕,代表此括号内的运算在得出结果后会被去除小数部分,只保留整数部分。比如〔18.5〕=18、〔-64.12〕=-65、〔0.1〕=0。 y = x -〔(5a + b + c - d - 5e)x p〕 y······最终价格 x······基准价格 p······该项交易的交易选项价格乘数,一般是0.05或0.2(pricemultiplier) a······major_positive类言论强度 b······minor_positive类言论强度 c······trading类言论强度 d······minor_negative类言论强度 e······major_negative类言论强度 (ps:中文minecraft wiki在这边犯了一个错误——顺序错了,请各位以前参考过相应内容的读者注意一下。英文minecraft wiki的对应部分是正确的。 这个错误在2020年6月17日16:31的id为的版本中出现,在2022年5月2日被修复。——2022年5月2日作者注) 举个例子,假设一位村民对一位玩家拥有如下言论: minor_positive:25 major_positive:20 minor_negative:5 major_negative:15 trading:4 那么对于一项原本价格为5绿宝石、乘数为0.05的一项交易来说,最终的价格应该是: y = 5 -〔(5x20+25+4-5-5x15)x0.05〕 y = 5 -〔2.45〕 y = 5 - 2 y = 3 当然,y肯定不能等于甚至小于0,mojang规定了y≥1。所以如果y<1的话,y就会被游戏调整到1,也就是仅仅只需要1个绿宝石就可以了。 说到交易系统,这就不得不提到村民的第三个重大改动:村民的交易更加高级了。 还记得上一章我们自定义交易时,遇到的那个careerlevel标签了吗?在更新前,careerlevel基本上在游戏中没怎么体现。但更新后,村民立马就有了等级之分:新手、学徒、老手、专家和大师。 当然,说是有了等级之分,实际上本质和更新前的差不多,这里就不多叙述了。 第四个重大的改动,就是村庄有了声望系统。这里需要注意一点,声望≠言论。言论的单位是一个个村民,影响的是各个村民本身,跟村庄无关。而声望系统的单位是村庄,会影响到村庄内的所有村民以及铁傀儡。 每个玩家在不同村庄都有一个声望值,声望值的高低会影响到村民交易的折扣程度以及铁傀儡(自然生成的)是否和玩家敌对。声望的初始值为0,当玩家在村庄内发生不同的行为时,会影响到玩家在村庄内的声望,可能是加,也有可能是减,但不管怎样,声望值肯定不会高于30或低于-30。 当一名玩家在某个村庄内的声望值等于甚至小于-15时,该村庄的铁傀儡(不是玩家召唤的)将会与玩家敌对,直到玩家的声望重新高于-15。 如果一个村庄没了,即村民全部没了或床全没了,那么玩家在这个村庄的声望也就会没掉。 ...... 根据minecraft wiki用户nickid2018于2022年12月4日所作的修改,可得知声望其实就是和言论在一起的,言论和声望一起构成了一整个系统,所以上面这些关于第四个重大改动的描述,完全是错误的,请不要相信。 (中文wiki上村民的条目的错误真的好多) 这才是真正的第四个重大改动: 第四个重大的改动,也就是村民的繁殖系统。 在更新前,村民如果要繁殖必须要达成以下条件: 1.至少有两个同村庄的村民并拥有充足的食物 2.当前村庄的成年村民数量并没有达到该村庄有效门数量的135%[java版]或200%[基岩版] 3.村民有繁殖意愿(这有很大几率会在玩家与村民交易后出现) 在更新之后,这些条件变成了: 1.至少有两个同村庄的村民并拥有充足的食物 2.当前村庄的人口数少于床数 3.村民有繁殖意愿 4.床的上方要有足够的空间来让幼年村民玩蹦床(?) 5.在近期,村庄内没有村民死亡 本章就讲到这里吧,虽然还有许多内容没有讲到,但也无伤大雅,毕竟那些内容与指令比较没有关系。 第一百五十六章 村庄与掠夺更新后的自定义交易 在开始本章的主要内容之前,容我先讲几句话。 看起来我已经有一两个月没更新了,但其实这些天来我一直在高强度更新。更新什么呢?以前的章节。 为什么我要去更新以前的章节呢?因为随着mc版本的更新,以及时间的流逝,加上我当时没什么写教程的经验,以上种种因素导致以前的章节出现了许多错误和疏漏之处,因此我开始进行一次大修,我称之为『本书第一次大修』。这个大修主要是对本书113章之前的内容进行修改,工程量十分的巨大。但好消息是,截止2022年7月25日,本书已经基本完成了从序言到第九十章的修改。因为改动巨大,所以我强烈推荐各位抽点时间重看一遍,特别是自计分板之后的内容,几乎每章都有重写。 大修预计将会在8月初结束,不出意外的话,届时我将会重新恢复相对比较高的更新频率。另外,如果你是在一些盗版网站上阅读本书,建议你来起点读书或红袖添香等正版网站来看,不然盗版网站可不会对之前的章节进行更新。 回到正题。 —————不华丽的分割线————— 黑夜将至,忘记带床和羊毛的你,虽然身披下界合金套装,但源自内心对黑暗的恐惧仍然使你感觉到些许害怕。行走在积雪的桦树森林中,你想起刚刚开启这个存档时,虽然挖三填一度过了危险的夜晚,但仍然一出来就被骷髅射死的窘迫场面。 低头看了看手上拿着的海洋探险家地图,再次抬头时,你看见前方似乎有一些亮光。你以为这是岩浆湖的亮光,但随着你的前进,亮光背后的房子冒了出来——前方是一个村庄!兴奋的你跑了过去,那房子越来越近。但奇怪的是,这房子后面并没有任何其他房子,直到你快要到达那里时,才发现这个房子建在悬崖上,村庄本体其实在悬崖下面。 一个村民从你旁边走过——他看起来像是这栋房子的主人。此时你冒出了个点子——趁着村民不注意,把他挤下山崖。这个想法很成功付诸实现,然后你就一觉睡到天亮。 次日清晨,你来到山崖下的村庄,手上拿着刚刚从田里摘的胡萝卜。突然有一位手中抱着绿宝石的农民兴冲冲跑到你的面前。你打开了这个农民的交易界面,他是一位没有任何经验的新手农民,提供两项交易: 22胡萝卜→1绿宝石 15甜菜根→1绿宝石 你突然来了兴趣,想要和这个村民交易亿下。很快你就把村庄里所有胡萝卜给摘了,加上你背包里原有的胡萝卜,总共215个。你和他进行了5次交易,花费110根胡萝卜拿到5颗绿宝石,村民也刚好获得足够的经验升到了『学徒』级,并附带生命恢复效果。 升到『学徒』级之后,村民新开放了两个交易: 6南瓜→1绿宝石 1绿宝石→4南瓜派 你先把剩下的胡萝卜花光,然后拿着得到的9颗绿宝石加上自己原先的3颗绿宝石买了48个南瓜派,这一项交易就没货了,村民也成功升级到『老手』级。到了老手后,村民又开放两个新的交易,且由于好感度的提升,交易开始打折。你继续和村民交易,让他继续升级.......十几分钟后,村民成功升级到了『大师』级。 升级到『大师』级别之后,村民的经验条消失,也就是无法再次升级。你也得到了一堆的交易品和大量的经验值。将交易品装入潜影箱后,你继续朝着海底神殿的方向进发。 如上文所见加上你的经验,可以得出,在村庄与掠夺更新后,村民的交易系统有这么几个特点: 1指定的村民职业具有指定的交易项目。 2有职业村民具有经验系统和等级系统。等级分为5级,从低到高分别是『新手、学徒、老手、专家和大师』。村民可以从交易中获得经验,经验可以用来提升自己的等级,每提升一次等级,升级到下一级所花费的经验值会更多。 3每个交易项目都可以用一到两种物品换取指定的物品。 4玩家也能够从交易中获得一定的经验。 5交易项目具有次数限制,次数限制达到后将无法使用该交易项目,需要村民前往工作站工作并补货后,交易项目才能重新开放。 6每个交易项目的价格都会受到该村民言论以及其他因素的影响,可能会上浮也可能会打折。 上面这六个特点其实与村民nbt标签中的这些标签有关: 1vigerdata(复合标签) 2vigerdata内的level、xp和一个交易项目中的xp(均为int整形) 3一个交易项目中的buy、bugb和sell(均为复合标签) 4一个交易项目中的rewardexp(byte布尔值) 5brain(复合标签)和一个交易项目中的maxuses(int整形) 6gossips(复合标签列表)和一个交易项目中的demand、specialprice和pricemultiplier(前两者为int整形,后者为float单精度浮点数) 为了在村庄与掠夺更新后也能够使用nbt自定义交易,我们得先来看看村民职业方面的改变。 在1.14版本之前,村民有一级职业(profession标签决定)和二级职业(career标签决定)。而在1.14版本更新后,就没有什么一级二级之分,所有职业都有了单独的命名空间id,如农民就有了minecraft:farmer。并且由于职业不再分一级二级,所以在新版本只有一个标签决定着村民的职业:vigerdata复合标签下的profession标签。 profession标签的值就是该村民的职业id。截止java1.19版本,原版村民14个职业的id分别是: minecraft:armorer——盔甲匠 minecraft:butcher——屠夫 minecraft:cartographer——制图师 minecraft:cleric——牧师 minecraft:farmer——农民 minecraft:fisherman——渔夫 minecraft:fletcher——制箭师 minecraft:leatherworker——皮匠 minecraft:librarian——图书管理员 minecraft:mason——石匠 minecraft:nitwit——傻子(这也是职业?) minecraft:shepherd——牧羊人 minecraft:toolsmith——工具匠 minecraft:weaponsmith——武器匠 举个例子,假设我们要生成一个农民,只需要这样子: \/summon viger ~~~{vigerdata:{profession:“minecraft:farmer“}} 然后游戏就会生成一个没有任何职业的村民。等等,怎么不是农民? 因为我们没有指定工作站点。村民由于没有工作站点,所以就变成了无职业的村民。我们会在待会了解到如何解决这个问题。 vigerdata内不仅仅有profession标签用来决定村民职业,还有另外两个比较重要的标签: level(int整形)——村民的职业等级,新手为1级,大师为5级。如果设定的等级高于职业的最高等级,村民将不会开放新的交易项目。(没错,这就等同于1.14更新前的careerlevel标签) type(字符串)——村民的种类,它指定了这个村民是沙漠村民(minecraft:desert)还是平原村民(minecraft:ins)还是其他类型的村民。 其中的type标签不用管,除非你想要给村民弄点儿不一样的衣服。我们重点看看level标签。举个例子: \/summon viger ~~~{vigerdata:{profession:“minecraft:farmer“,level:5}} 这将会生成一个大师级别的农民。等等,怎么不变回无职业了? 正常情况下,level字段只能由交易改变,也就是说玩家是个关键因素。新版本的村民虽然有『工作站没掉就失业』的性质,但如果游戏发现这个村民好像和其他玩家交易过,就不会让这个村民失业。在这边,由于我们改变了level标签的值,导致游戏认为这个村民已经和玩家交易过了,所以这个村民不会失业。 上面这些也是1.14更新后与自定义交易关系相当大的内容,接下来我们来看看同样也是1.14更新后自定义交易的核心:offers标签。 offers标签的内容其实变化并不大,我们在第一百五十四章所讲的内容可以完美适配过来,因此这里就不细讲那些重复的内容。我们就重点来看看1.14更新后,在交易项目中添加的4个新标签: xp(int整形)——村民每次交易能从该交易项目中获取的经验值 demand(int整形)——价格调整因素之一:供需关系 specialprice(int整形)——价格调整因素之二:特惠 pricemultiplier(float单精度浮点数)——价格调整因素之三:价格乘数 xp标签我们就不讲了,做自定义交易干嘛要管村民升级。我们重点来看看后面三个标签,这三个标签十分重要,因为它们关系到一个非常重要的东西:价格 在村庄与掠夺更新后,每个交易项目的第一个收购项,也就是buy复合标签所规定的物品,其数量,也就是价格,会发生变化。所以我们有一个专门的公式来计算村民收购的第一个物品的最终数量,也就是价格的计算公式: (此公式更新于2022年12月28日,仅适用于java版) 当a≥0且v≥1时 e=-〔(5a + b + c - d - 5e)x p〕-〔((v-1)x0.0625+0.3)xm〕+f y = mp(〔axpxm〕+m +e, 1 ,m) 当a<0且v≥1时 e=-〔(5a + b + c - d - 5e)x p〕-〔((v-1)x0.0625+0.3)xm〕+f y = mp( m +e, 1 , m ) 当a≥0且v<1时 e=-〔(5a + b + c - d - 5e)x p〕+f y = mp(〔axpxm〕+m +e , 1 , m ) 当a<0且v<1时 e=-〔(5a + b + c - d - 5e)x p〕+f y = mp( m +e , 1 , m ) 参数列表 a······该交易项目demand标签的值 f······该交易项目specialprice标签在玩家打开交易界面之前的值 p······价格乘数 m······原价 y·······最终价格 e······该交易项目specialprice标签的值 a······major_positive类言论强度 b······minor_positive类言论强度 c······trading类言论强度 d······minor_negative类言论强度 e······major_negative类言论强度 m······村民收购的第一个物品的堆叠上限 v······玩家的村庄英雄效果等级(v 1即无村庄英雄效果) 其中,作者自己定义的六角括号〔〕,代表此括号内的运算在得出结果后会被去除小数部分,只保留整数部分。比如〔18.5〕=18、〔-64.12〕=-65、〔0.1〕=0 上面的mp(a,b,c)函数,则用来限制a介于b、c之间(b≤c)。比如: mp(34,1,3)=3 \\\\ 34超过了最大值3,所以输出3\\\\ mp(12,8,88)=12 \\\\ 12介于8和88之间,所以还是输出12\\\\ mp(-44,9,73)=9。 \\\\-44低于最小值9,所以输出9\\\\ 你可能会感到疑惑:唉这个公式怎么和上一章的公式完全不一样啊? 这个问题很有趣。首先,上一章的公式仅仅只考虑了言论对价格的影响。仔细观察,你也会发现这里的公式中含有上一章的公式。那这有趣究竟在哪里呢? 上一章的公式来自minecraft wiki。在中文minecraft wiki的村民页面上,还有另一个价格计算公式。而这个公式,对于声望的计算,是完全不一样的! y = m -〔(5a + b + c - d - 5e)x p〕 \\\\仅考虑言论的价格公式\\\\ y =〔axpxm〕+〔pxd〕-〔pxcx10〕+e+m a······该交易项目demand标签的值 p······价格乘数 e······该交易项目specialprice标签的值 m······原价 c······trading类言论强度 d······minor_negative类言论强度 \\\\ minecraft wiki上的计算公式\\\\ 于是,作者基于这两个公式,通过一些实验,总结出了上面的那个计算公式。 但不管如何,这个错误仍是一个较为严重的错误,因为它已经存在了很长时间,并有许多教程引用了这个公式,影响范围较大。 需要注意的是,上述公式都有涉及到言论系统,但言论系统目前(2022年12月28日)仅仅存在于java版中,所以上述公式不一定适用于基岩版。 ps: 2022年12月4日,minecraft wiki的用户nickid2018终于将百科的计算公式改了。新的计算公式如下: e =声望影响的降价+村庄英雄效果影响的降价 y = mp(mx〔1+axp〕+e,1,m) a······该交易项目demand标签的值 p······价格乘数 e······该交易项目specialprice标签的值 m······原价 m······村民收购的第一个物品的堆叠上限 这个公式与上面作者自己得出的公式相差不大,但仍有一个可能的问题: e(specialprice)的值的计算方式可能有误 要说明为什么有这个问题,我们得先了解一下specialprice的机制。 当一名玩家打开村民的交易界面时,游戏会计算每个交易项目的实际价格。这时候,游戏会先计算言论和村庄英雄效果的影响,并将它们的值加到每个交易项目的specialprice标签中。第二步,游戏才会根据demand等其他标签,综合计算出每个交易项目的值。在这个过程中,specialprice标签会加到计算的值中。第三步,也就是向玩家展示这些交易项目。最后,当玩家关闭村民的交易界面时,游戏会把每个交易项目的specialprice标签清零。 也就是说,如果要使得交易打折,specialprice的值必须要为负。 但是,如果根据minecraft wiki的计算方式,specialprice为负的情况只有一种可能:村民对于玩家具有过多的负面言论。而这是不可能的。 当然,我们也别过多纠结这个问题,该改正的总会改正,只不过是时间问题。我们更加需要关心的有两件事情: 1.我们肯定不希望我们自定义的商品价格被随意改变,所以我们该怎么办呢? 2.specialprice的性质可以弄出什么效果呢? 对于第一个问题,我们的解决方法很简单——仔细观察上面的公式,我们不难发现『p价格乘数』都是一个及其重要的变量。 既然是『乘数』,如果我们把这东西改为0,那问题是不是就解决了? 试一试!当p=0时 e =-〔(5a + b + c - d - 5e)x 0〕-〔((v-1)x0.0625+0.3)xm〕+f e =-〔((v-1)x0.0625+0.3)xm〕+f y = mp(〔ax0xm〕+m -〔((v-1)x0.0625+0.3)xm〕+f, 1 ,m) y = mp(m -〔((v-1)x0.0625+0.3)xm〕+f, 1 ,m) 不难发现,就算p=0解决了大多数问题,但村庄英雄效果和specialprice的原始值仍然会影响到价格。但村庄英雄效果毕竟是很难得到的,specialprice的原始值又是只能通过命令改变,所以总体上来说影响很小。 总结下来,相比更新之前,我们在新版本中自定义村民交易,还需要注意将价格乘数pricemultiplier设为0.0(有没有一种可能,不设置其实也默认是0)。举个例子: \/summon viger ~~~{vigerdata:{level:6,profession:“minecraft:farmer“},offers:{recipes:[{rewardexp:1,maxuses:,buy:{count:1,id:“minecraft:diamond“},buyb:{count:10,id:“minecraft:emerald“},sell:{count:1,id:“minecraft:diamond_sword“,tag:{enchantments:[{id:“minecraft:sharpness“,lvl:10}]}},pricemultiplier:0.0}]}} 这个例子是我们第一百五十四章的一个旧版例子的新版写法,只不过将暮色森林mod的幻影骑士战利品换成了普通的钻石。 上面这条指令将会生成一个等级为6的农民,并带有一个『具有15万次使用次数、每次交易返回1点经验值、价格乘数为0.0、能够用1钻石加上10绿宝石买一个附魔有锋利x的钻石剑』的交易项目。 那对于第二个问题呢? 既然游戏在计算specialprice时会将specialprice的初始值加上,那么只要控制得当,在玩家打开交易项目之前就更改specialprice的值,就能做到自定义折扣。 另外,修改specialprice的值并不会影响到村民给正在交易中的玩家的商品价格。 村庄与掠夺更新后的自定义交易到此就结束了,你现在可以尝试去自定义一个新版本的村民,看看效果如何。 附表:新版本村民历史 java 1.14——对村民进行了大改 1.14.3\/1.14.4——优化 1.15——傻子村民现在没有徽章,村民会被玩家赶下床 1.16——优化 1.16.2——工作站点优化 携带\/基岩版 1.10.0——大改 1.11.0——优化 1.13.0——村民现在会在战胜袭击后欢呼 1.16.220——村民现在不再能够穿墙过去睡觉 1.18.10——村民现在会发射烟花火箭庆祝,交易时头顶不会再出现绿宝石图标 1.18.30——优化 第一百五十七章 初识npc 2016年8月29日,mojang发布了携带版alpha 0.16.0 build 1。在这个版本中,首次出现了一种新的实体——npc(non-yer character非玩家角色)。这种实体具有一些村民的特性,比如胸前粘在一起的手和与村民一样的音效。但它们的外观相当不同,甚至还有非人哉的外观。 在随后的数次更新中,npc逐渐拥有了与玩家对话、让玩家选择的能力。但这时候,npc仍只能在教育版或打开了教育版模式的基岩版中发挥作用,这就使得它的使用受到了很大的限制。直到那个改变了整个minecraft基岩版开发界的版本—— minecraft:基岩版 1.16 由于gametest(游戏测试)框架的引入、2018版脚本的放弃支持、一堆新指令的加入等等重大更改,可以肯定,基岩版1.16版本称得上是近些年来基岩版最重大的转折点。在之前你应该也已经注意到,许多新奇的基岩版指令往往就是在1.16版本加入。npc虽然不是指令,但由于它和指令高度的关联性,因此也不例外。 1.16.0版本更新后,npc终于能够独自在基岩版中使用而不需要开启教育版模式。并且随着官方加大力度更新gametest框架,npc可能将会在不久的将来成为基岩版行为包开发的重要一部分。所以,说了那么多,那么npc到底如何生成、有什么用、又如何使用? 生成当然是及其简单的,你或许已经知道该如何生成: 1使用\/summon npc——直接使用summon指令生成 2使用\/give @s spawn_egg 1 51——获取npc的刷怪蛋 现在,你应该已经生成出了一个npc。让我们先观察一下这个npc(图157-1)。 如无意外,你应该看到的是一位留有黑色长发、不知道是男是女、有大鼻子、斗鸡眼、穿着土色t-shirt和青色长裤、头上飘着一串黄色npc的人。这就是npc,或者更准确的说,这就是使用了默认皮肤的npc。 npc有许多皮肤。截止基岩版1.19.51版本,npc已经拥有了多达60种皮肤。虽然npc能够更改皮肤,但这并不意味着我们能够随便给npc换皮肤,npc可不是玩家。 npc上方显示的名称就是npc自己的名称。但npc的名称比较特殊——在npc的nbt里面,npc的名称存储在nametag标签里面,而并不是customname标签里。如果你并没有把之前章节的东西丢掉,你应该还记得customname标签的作用,也就是用来存储实体的名称。npc的名称存储在另一个单独的标签内,就会引出一件麻烦事——使用重命名刷怪蛋或summon指令的方式都不能改变npc自己的名称。只不过根据网上一些使用npc做浮空字的教程来看,似乎在网易版,npc的名字就是实体名字,但作者毕竟不玩网易好久了,自然也就无从验证。 现在,让我们打开npc的界面(图157-2)。 npc的gui界面十分简单,仅由四个主要部分组成(顺序从上到下): -名称输入框:可以更改npc的名称,并且可以使用格式化代码§。最大可输入128个字符,但有效输入(也就是真正能够显示出来的)只有前32个字符。 -对话编辑按钮:这是一个按钮,按下去可以进入到另外一个界面,以编辑npc与玩家的对话。 -皮肤选择栏:可以更改npc的皮肤,左右的按钮可以翻页。 -高级设置按钮:这也是一个按钮,按下去也是可以进入到另外一个界面,在新的界面里可以为npc添加指令。 需要注意,如果你发现你一打开npc就只是个空白的对话界面,则说明你没有worldbuilder(世界管理员)权限。这个权限不等于op权限,默认情况下创造模式玩家会自动拥有这个权限,在开启教育版模式的情况下也可以通过\/ability或\/worldbuilder(\/wb)指令手动赋予。总而言之,请你先将你的游戏模式调成创造模式,然后再打开npc。 还需要注意,如果你左键(键鼠输入)或点击了npc(不是长按),那么npc将会被删除。现在由于npc没有被编辑所以没什么,但当你已经弄好时不小心将它点没了,你估计会破口大骂mojang为什么没有给minecraft加入ctrl+z。特别是触控,十分容易误触!因此,我建议你勤劳一点,指令和对话先在外面写再复制到游戏中。 我们本章就重点来了解npc的两部分:对话和高级设置。 按照顺序,让我们先来看看对话。 按下对话编辑按钮,我们就进入了一个空白的对话界面(图157-3)。 对话界面主要由两部分组成:npc外貌的渲染图像和对话框。 由于是编辑模式,所以我们可以在对话框中直接输入一些东西。对话框最大可以输入1000字符(1.19.51版本作者实测),但minecraft wiki上却说最大是256字或在少数情况下是337字,更加离谱的是官方文档又说对话框有307字符的限制(时间为2022年12月29日)。所以——实践是检验真理的唯一标准,这句话永不过时。 回到正题,对话框就像是个文本编辑器一样。如果超出它的显示能力,它的右侧就会出现滚动条,你可以通过滚动对话框来继续编辑或阅读。 让我们尝试输入点东西,比如输入『你好!』,然后关闭对话编辑界面。需要注意,你应该已经注意到右上角有两个关闭按钮了。上面那个关闭按钮将会直接关闭整个界面,而下面那个关闭按钮仅仅只会关闭对话编辑界面然后返回到最初的编辑界面而已。放心,不管是哪个按钮,你在对话框内所写的任何东西都是不会丢失的,它可是实时保存的! 这就是编辑npc对话的方式,其实相当简单。接下来让我们来看看npc的高级设置。 按下『高级设置』按钮,你就来到了『高级npc设置』界面(图157-4)。 这个界面看起来特别空,就写着两句话(单击此按钮在npc对话框中添加命令。可以同时添加多个命令)和一个『添加命令』按钮。那如果点一下按钮呢?(图157-5) 在『添加命令』按钮的上方,原来的两行文字消失了,取而代之的是一块『命令』面板。在这个面板上,有一个命令输入框,输入框右边是一个大大的『+』按钮,下方是三个开关,从左到右分别是『按钮模式』、『进入时』和『退出时』,其中『退出时』已经打开。在面板的右上角,还有一个小型的垃圾桶按钮。 点击垃圾桶可以删除这个面板以及上面的所有设置。面板的核心部分——命令输入框——看起来和命令方块的很像。但两者有两个重大区别。首先,npc的命令输入框最大只能输入1024个字符,但命令方块能够输入个。其次,npc的命令输入框可以换行,每行都可以写一个指令,执行时会按照从上到下的顺序执行,而命令方块不能换行且只能写入一条指令。 输入框右边巨大的『+』,点击它可以放大输入框。但这输入框目前实测有一个问题——虽然上限是1024,但写的内容超出了界面之后竟然就无法往下滑,仅仅只显示个省略号。 下方的三个按钮,用途是设置上面的命令会在什么情况下触发运行。默认是『退出时』,即在退出对话界面时会触发运行。需要注意,还记得刚才提到退出界面有两个关闭按钮吗?如果你点击下面的关闭按钮来退出,那么指令会正常运行(除非你处于编辑模式);如果你点击上面的按钮退出,那么指令反而不会运行(bugjump正常在线)(1.19.51版本实测)。 我们可以将指令的触发方式改成『进入时』或『按钮模式』。『进入时』,也就是玩家一打开npc对话界面,就会触发指令运行,除非此时你处于编辑模式。『按钮模式』是一个比较特殊的触发方式,在你选择了这个模式之后,在三个按钮下方还会出现一个文本输入框,在这里你可以输入按钮显示的文本。这个文本输入框可以输入至多128个字符,但只有前16个字符才会真正有效显示出来。当你添加了触发方式为『按钮模式』的指令后,再打开对话界面,在『npc的渲染图』和『对话框』下面将会出现一些按钮,上面显示着那些你自定义的文本(如果你啥也没写,按钮将不会显示任何文本)。点击这些按钮将会运行相应的指令,并且在指令运行完后对话窗口将自动关闭,如果此时还有设置退出时执行的指令,那这些指令也将会执行。 有趣的是,即使是在编辑模式下,你点击那些按钮,『按钮模式』的指令和『退出时』的指令(如果有)也能照常运行,这就省去了手动更改游戏模式的麻烦。 上面说到命令输入框可以换行,每行可以写一个指令,运行时从上到下运行。这时候可能就有问题了——如果有一行指令写错了会怎样? 答案是不会怎样,游戏会直接跳过这一行指令继续执行下去,直到没有指令可以执行。举个栗子: give @initiator diamond 1 0 tellraw @initiator {“rawtext“:[{“text“:“§a您获得了一颗钻石!§r“}]} wtf?! say§e @initiator§r获得了一颗§b钻石§r! 当上面这些指令被运行时,你的聊天栏将会显示: 您已被给予钻石*1 您获得了一颗钻石! [npc]你的游戏名获得了一颗钻石! npc在运行到『wtf?!』一行,并没有因为『wtf?!』是错误的指令而停止执行,反而是连错误信息都不放一个就继续执行下去。 你应该注意到了,在上面的指令中,出现了一个奇怪的目标选择器:@initiator 什么是『@initiator』?它指代了什么东西? 让我们回想一下第四章『目标选择器』的内容,或许你能想起来在第四章曾讲到: 『@initiator——代指正在与该npc交互的玩家[仅基岩版],不管这名玩家是否在交互时被杀死』 @initiator指代的就是正在和运行指令的npc交互的玩家。这或许是目前最难记下来的目标选择器变量了吧。 回到这个『命令面板』上来。『命令面板』并不能无限制添加,一个npc最多就只能添加6个『命令面板』。但考虑到一个『命令面板』就可以放下来许多条命令,实际上没什么影响。 现在,我们已经知道了如何获得和使用npc。但是,如果我们要把npc投入实践,我们就不得不面对一个问题:npc会不会被击杀? 这个问题的答案肯定是能的,你只需要用一些方法将npc推下虚空(它们还是会受重力影响的),然后npc就会死亡。 我们需要对这个问题作出一些限制,也就是:npc能否通过正常手段击杀? 这个问题的答案是『不能』。npc可以免疫几乎一切的伤害,包括——摔落、爆炸、生物攻击、玩家攻击、火焰灼烧、冰冻、窒息、药水效果等等等。基本上,npc对于没有权限的玩家来说不可击杀。 因此,放心使用npc,官方出品的怎么可能会是不保险的呢?虽然mojang确实搞出过很多不保险的东西。 这就是本章的全部内容,但这仅仅是npc的冰山一角。我们将在以后了解到更多有关于npc的内容。 ————历史———— -携带版\/基岩版 0.16.0——加入又移除了npc,但没有完全移除。 1.0.0——重新加入了npc。 1.8.0——能够使用\/summon指令生成npc了。 1.10.0——现在不能使用\/summon指令生成npc,但npc现在有功能了。 1.12.0——现在npc又没功能了。 1.16.0——现在能够获取到npc的刷怪蛋,也能够使用\/summon指令生成,同时npc又有功能了。npc也不再是只有20点生命值。 1.18\/1.19——加入了一堆皮肤 -教育版 1.0——加入了npc 1.14\/1.18——加入了一堆皮肤 第一百五十八章 重新认识nbt 看到这个题目,你是不是大吃一惊?nbt怎么还要重新认识? 别太惊讶。还记得最开始我们接触到nbt的时候吗?在第五十四章的最后,我指出这其实并不是真正的nbt,而是mojang专门搞出来给人看的『snbt』,即『stringified nbt』,『字符串化的二进制命名标签』。在之后的章节,我们也重点了解了snbt,知道了它的格式和使用方法。而现在,我们已经了解并掌握了许多物品和实体的nbt,这时候,也是时候来认识一下真正的树状结构的nbt,这样子你才能真正理解接下来的内容。 —————分割线————— 树,是大自然的鬼斧神工。它提供了人类赖以生存的氧气和食物,也给了人类许多灵感。 一棵树,有树根、树干、树叶。它们均发源于一点,我们可以把这一点称为——根(root)。为了方便讲解,我们接下来忽略位于地底下的树根,只看树干和树叶。 树干上有许多分叉点,我们可以把这些分叉点称为——节点(node)。通过节点可以长出一些树叶或新的树干,在新的树干上则又有许多新的节点,分叉出更多的树叶和树干。 一个节点所分叉出的所有树叶和树干,以及这些树干上所有的节点,可以全部视为这个节点的值(value)。你可以这么理解——这些树叶和树干,就是这个节点所存在的价值。如果没有这些树叶和树干,那么这个节点也将不复存在。 这就是一棵树——一颗完全由根、节点和值构成的树!(图158-1) 根其实是一种特殊的节点,它是整个树的开始,所以整个树都可以看作是根的值。 除了根,其他节点都可以取名字。在同一个树干上,每个节点的名字都必须是独一无二的,以防与其他节点弄混。 比如,我们可以给根上面的第一个节点取名『apple』、第二个节点取名『beluga』。这样子,我们就不容易搞混这两个节点,也可以方便用名称指代这两个节点。 假设第一个节点长出了一条树干,上面也有一个节点,我们给它取名为『cen』。而这个『cen』节点也长出了一条树干,上面也是有一个节点,我们给他取名『sama』(图158-2)。那么,如果其他人也要寻找『sama』节点,该如何寻找呢? 假设其他人只知道这个节点叫『sama』然后去寻找它,在节点很多的情况下这无疑是大海捞针。而且有可能在不同树干上的其他节点也叫『sama』。这时候该怎么办? 我们来看一个现实生活中的情景: 你此时正在学校里上课,老师要求你将书翻到这节课要讲的『第三模块第五单元第一课』。你肯定是先找到『第三模块』,然后找到『第五单元』,最后找到『第一课』。老师不可能只告诉你『翻到第一课』,因为每个单元都有自己的第一课。老师这样说,让你得知了『第一课』的路径(path),于是你才找到了这节课要讲的『第一课』。 回到上面的问题,答案已经十分明显了——那位要寻找『sama』节点的,应该去询问得知『sama』节点具体位置的人,比如我们。然后我们应该将『sama』节点的路径告诉他,也就是: apple.cen.sama 这就是『sama』节点的路径。如你所见,一个路径就是『节点.节点.节点』的形式,从左往右的节点指出了一条从根开始通向终点节点的具体道路(图158-3)。 路径既然可以用来找到节点,那么他们应该也就能够表示节点,乃至于表示这个节点的值。毕竟『一个节点』只对应『一条路径』,『一条路径』也只对应『一个节点』,『一个节点』也只能有『一个值』。因此,如果我们再一次看向『sama』节点的路径『apple.cen.sama』,我们就会发现『apple.cen.sama』既可以用来表示『sama』节点,也可以用来表示『sama』节点的值。(只不过sama节点的值是空的) 又比如说,路径『apple.cen』既表示节点『cen』,也表示节点『cen』的值——从『cen』节点长出的树干以及上面的『sama』节点。 看起来像『节点.节点』这样的路径解决了寻找节点以及节点的值的问题,但如果『apple』节点又长出了一条新的树干,这条新的树干上又有一个节点『touhou』该怎么办(图158-4)?此时『sama』节点的路径又该如何表示? 很明显,现在『apple』节点长出了两条树干(另外两条是贯穿apple节点的从根长出来的主干,其实是一条,不要搞错了),我们需要有一个正确的方式来表示这两条树干。比如我们可以取名字,但这似乎过于麻烦了,而且容易把树干和节点搞混。最好也最简单的方法就是给树干编『号数』,也就是使用索引(index)。 将节点『cen』所在的树干编上索引0,那条新的树干编上1,然后我们只需要在路径中的『apple』后面,『.』前面加上树干的索引,就大功告成了: apple[0].cen.sama 其中,[0]指的就是索引为0的树干,也就是『cen』节点所在的那一条。通过这种方法,我们也可以表示『touhou』节点: apple[1].touhou 不过,这些东西跟nbt有什么关系呢? 这个问题问得好。现在,让我们再来看看另外一颗树(图158-5): 根 │ ├id:“minecraft:jukebox“ ├isying: 1b │ ├ recorditem: │├count: 1b ││ │└id:“minecraft:music_disc_ward“ │ ├x:-1 ├y: 60 ├z:-53 │ ├recordstarttick: 0l └tickcount: 514l 仔细看这东西,你有没有发现? 如果没有发现,那让我们把这棵树的形态转化一下,变成: {id:“minecraft:jukebox“,x:-1,y:60,z:-53, isying :1b, recorditem :{count:1b,id:“minecraft:music_disc_ward“}, recordstarttick:0l, tickcount:514l} 这不就是snbt吗? 没错,上面那棵树,其实就是下面这个snbt的nbt形式,游戏所看到的nbt就长这个模样。 这棵nbt其实就是一个放在(-1,60,-53)的唱片机的方块实体。我们会在第十八卷具体了解到方块以及方块实体的内容,在这边你只需要将方块实体当作是方块nbt即可。从这棵nbt中,我们和游戏都可以得知,这个唱片机此时正在播放(isying)ward唱片(recorditem),并且已经播放了25.7秒(tickcount),这个唱片机在此之前没有播放过任何唱片(recordstarttick)。 你可以在minecraft wiki上搜索『唱片机』来具体了解上述标签的作用,nbt都讲到这了你应该不可能看不懂minecraft wiki上关于nbt的内容吧? 回到这棵nbt树上,仔细观察它与它的snbt形式,你应该不难发现,id节点的树叶上写着『“minecraft:jukebox“』,x、y、z节点的树叶上写着『-1』『60』和『-53』,isying节点的树叶上写着『1b』,recordstarttick和tickcount节点的树叶上写着『0l』和『514l』。在snbt中,上面这些节点所对应的标签的值的类型都是字符串、int整型、byte字节型和long长整型。也就是说,string字符串、byte字节型、short短整型、int整型和long长整型,以及其他的浮点数数据类型,在nbt树中都无一例外承载于『树叶』之上。 而recorditem节点,长出的是一条树干,树干上有id和count节点。在snbt中,recorditem标签的值类型是复合标签,复合标签内也有id和count标签。也就是说,『复合标签』在nbt树中所体现出来的就是一条树干。 也就是说,整个nbt标签其实就是一个复合标签? 没错,确实是这样。 通过上面的观察,你应该已经总结出来了nbt树与snbt的一些对应关系,比如节点对应标签名,树干对应复合标签。那……列表呢?在nbt树中,列表又是长什么样子? 还记得上面的『apple』节点吗,我们在研究节点的路径(path)时,遇到了一个节点长出两条树干的情况。如果我们以snbt的形式将『apple』节点表示出来,其实就是这样的: {apple:[{cen:{sama:}},{touhou:}]} 在snbt中,『apple』标签的值就是一个复合标签列表!列表的顺序规定了列表内每个元素(element)的索引值(index)。和生活中数数不一样的是,列表的索引并不是从1开始,而是从0开始,这就是为什么我们给『cen』节点所在的树干标上索引0而不是1的原因。 同理,如果一个节点长出了一堆承载相同类型数据的叶子,那这个节点的值也是一个列表(或数组)。如果一堆值是列表的节点挤在一起,那这一堆节点所形成的大节点自然也是一个值是列表的节点,而且这列表还是列表的列表: {节点:[[{},{},…],[{},{},…],…]} \\\\它的snbt形式\\\\ 只不过,像这样的二维列表,甚至是三维列表,我们在之前都没有碰到过,在以后也很有可能不会碰到。 这就是nbt的树状结构,也就是真正的nbt。看起来讲了很多,但其实内容并不是很难,唯一的难点估计是语言比较枯燥。 但这并不是本章唯一的重点。你应该还记得刚才讲的『节点的路径』。相比于nbt的树状结构,我们会在接下来的内容中更常碰见节点的路径(path)。其实,这个『节点的路径』,就是nbt路径(nbt path)——用来从nbt数据树中指定一系列特定元素的描述性标签。 在接下来的\/data指令中,nbt路径是非常重要的一个东西,可以说只要你掌握了nbt路径,你就几乎掌握了\/data指令。我们会在下一章更加深入了解nbt路径,但在此之前,请你『务实一点,把nbt的战术打法,nbt树的这个理念先搞懂』——范志毅,国家minecraft指令教学前任大将军,此句话为他2013年6月15日在评价minecraft指令教学时所说的名言警句。 本章到此为止。 对了,2023新年快乐! 第2023章 新春快乐 本书自2020年初发布以来,已经过去三个年头了。现在是2023年1月22日00分00秒,在此我祝各位读者新春快乐、万事如意!!! 2022年间,本书仅仅更新了4章(没错,4章前就是2022年的『虎年快乐』),但这并不代表本书没有作为。在这一年,本书被翻新了约三分之二的章节,重写了约三分之一的章节,填满了『第一次大修』这个大坑。可惜似乎由于起点的屏蔽,很少人注意到这些变化。 但没事,在新的一年里,本书可能还会鸽个半年,之后将开始努力更新!之前的章节也会进一步修改完善,努力让各位能够尽可能地看懂、看明白! 现在已经很晚了,各位读者记得照顾好自己的身体,『阳』了之后可不能老是熬夜。早点睡,明天就是崭新的一天! 新春快乐! 第一百五十九章 深入了解nbt树和nbt路径 在上一章,你应该已经理解了什么叫作nbt树,但理解不代表会运用。要真正搞懂nbt树的理念,我们得投入实践,学会阅读nbt树甚至表示出一个nbt树。 nbt数据树常常会表示成下面这样的格式: [root或其他具体名称]:根、父级标签或其他具体的名称或描述 │ ├[名称]:值或描述 ...... └[名称]:值或描述 注:在上面的格式中,代表必定会出现,[]代表可能会出现(含义跟指令格式中的一样)。 许多网站和程序,比如minecraft wiki、常用的java版nbt编辑器nbtexplorer,都采用了上述格式来表示nbt。 举个简单的例子,在minecraft wiki上,java版书与笔的物品nbt是这么表示出来的: ? tag:父级标签 └? pages:书与笔的各个页面。 空└?:一个单页。每一页是一个字符串,不能超过个字符。 在上面的这个例子中,由于minecraft wiki使用一个图片标识来表示数据类型,所以这里用一些特殊符号来代替: ?——pound复合标签 ?——list列表 ?——string字符串 仔细观察minecraft wiki给出的nbt树,结合我们前面所学的知识,你应该不难得出上面这个例子所表示的意思: 『对于物品书与笔,在其物品nbt标签中的tag复合标签下,有一个名为pages的列表型标签。这个pages列表是一个由多个字符串类型的值组成的列表,每个值都代表着书与笔中的一页,且每个值都不得拥有超过个字符。』 什么?你很难理解?或许我们需要睁大眼睛,逐行研究上面的例子。 第一行:? tag:父级标签 根据上面的格式『[root或其他具体名称]:根、父级标签或其他具体的名称或描述』,我们不难知道这在表示一个名为tag的复合标签。同时,它被解释为『父级标签』,说明minecraft wiki在这里给出的nbt树是在描述这个标签的孩子(也就是值)。 等等,为什么minecraft wiki不直接从根开始,而是从这个tag标签开始呢? 回忆一下第十一卷的内容,tag标签是物品通用标签内的一个标签,用来储存物品的额外信息。所有额外的物品标签都在tag标签内,因此minecraft wiki不从根开始描述的原因也就不难理解——使文章详略得当。 问题解决,我们来看看第二行:└? pages:书与笔的各个页面。 最开始的└意味着在这里,nbt数据树的这条树枝上有一个节点,而且由于└没有继续向下延伸,因此这个节点是该树枝上最后一个节点。第二个?代表的意思很明确,即该节点对应的nbt标签是个列表。『pages』是该列表的标签名,而后面的『书与笔的各个页面。』是对该标签的一个描述。 第三行更加简单:└?:一个单页。每一页是一个字符串,不能超过个字符。 最开始的└不用说,?估计也不用说。但?后面的标签名称呢? 还是那句话,这是个列表,列表是由多个相同类型的值组成,而不是标签。换句话说,这部分nbt树实际上描述的不是个标签,而是个值,自然也就不需要给出名称,因为没有名称。 冒号右边的很明显,是个对值的描述,相信大家都看得懂这里的中文,我就不再阐述。 现在,你肯定已经拥有阅读minecraft wiki上nbt树状图的基本素养。来尝试一下下面的这个nbt树: ?实体数据值 │实体共通标签 │活体共通标签* │生物共通标签 ├?? size:史莱姆的大小。最小为0,即小型史莱姆大小;最大值为126,超过126的值将当作126处理。 └? wasonground:表示史莱姆是否正在接触地面。 图示: ??—— int整型 ?—— boolean布尔值(byte字节型) *minecraft wiki把生物共通标签给拆开了?啥时候多出个活体共通标签? 上面唯一需要注意的一点是,你应该知道byte字节型有两个种类的值,一个是普通的数值,一个是布尔值。为方便区分,minecraft wiki将布尔值类型从byte字节型中独立出来,成为boolean布尔值,但实际上在nbt中还是byte字节型。 这里就暂时不放参考答案(实际上是因为懒得写),相信大家都能够看懂上面的nbt树状图。 搞懂nbt树状图后,接下来让我们继续了解nbt路径。 在上一章,我们基本上搞清楚了nbt路径是什么。比如对于下面这个nbt路径: apple[0].cen.sama 你应该知道它有三个意思: 1这代表sama标签的路径,你可以通过这个路径来找到这个标签 2这代表sama这个标签 3这代表sama这个标签的值 而在minecraft中,nbt路径最常见的意思就是第二和第三个——代表一个标签和或其值。或者说,nbt路径最常见的作用,就是用来寻找并获取到一个标签,然后对这个标签的值进行一些操作。 举个简单的例子,还记得你在第一百零八章掉下来的钻石吗?把它拿过来再看看: {age:0s,health:5s,pickupdy:0s,item:{count:1b,id:“minecraft:diamond“} ↑↑↑这是你掉的钻石的nbt,需要注意这只不过是一个简化版↑↑↑ 如果我们要使用\/data指令来获取到这颗钻石age标签的值,这个nbt路径该怎么写? 很简单,就一个单词: age 然后在聊天框中就会返回:0s 但其实你也可以这么写: {health:5s}.age 这是怎么一回事?前面的{health:5s}是咋冒出来的? 这虽然是个多此一举的写法,但我们从中也可以了解到nbt路径的一个特殊功能:匹配特定的nbt标签 有时候,我们固然想要得到一个标签的值,但当我们想把范围缩小时,比如想要获取所有钻石掉落物的age值,我们可能就无从下手。但其实,这有两种方法: 第一种,使用目标选择器;第二种,在nbt路径内加入一些匹配标签用的值。 其实这两种方法的原理都一样,但由于目标选择器的nbt参数我们不现在讲,因此先来看看第二种方法。 首先,路径『age』虽然是正确的,但其实在这里省略了一些东西。 什么东西?没错,根标签呢? 一般情况下,根标签都会被省略不写。如果不省略,那整个路径会变成: {}.age 其中,{}是根标签的路径,也就是代指根标签。由于根标签是个复合标签,所以用大括号表示。 然后,对比『{health:5s}.age』和『{}.age』,我们会发现两者唯一的区别就在于根标签拥有一个值:health:5s 很奇怪吧?明明路径就可以代表标签的值,为什么还要专门写一个特定的值呢? 其实,给路径中的一个标签加上值看上去多此一举,但实际上很有用。因为它有一个功能——过滤。 如果不加上health:5s,那么单独的{}将代表任何一个根标签。但如果加上health:5s,那么这仅能代表含有health:5s这个标签的根标签。 比如{health:5s}.age虽然能选中上面钻石的age值,但一定选不中下面这个钻石的age值: {age:-1s,health:s,pickupdy:0s,item:{count:1b,id:“minecraft:diamond“} 同理,对于路径『age』,我们也可以写成这样: age:100s 这看起来是一个snbt,但其实也是个路径,意思是寻找根标签内值为100s的age标签。 总而言之,如果给nbt路径内的某个或多个标签加上一个特定的值,那就能起到过滤的作用,使结果更加精确。 你现在应该知道如何获取所有钻石掉落物的age值吧?让我们试一试! \/execute as @e run data get entity @s {item:{count:1b,id:“minecraft:diamond“}}.age 返回: 钻石拥有以下实体数据:163s 钻石拥有以下实体数据:127s 钻石拥有以下实体数据:s (上面的data指令之后再解释) good!另外,你应该能解释『{item:{count:1b,id:“minecraft:diamond“}}.age』的意思吧?试一试描述一下它的意思。 上面的内容只是nbt路径的冰山一角,在下一章,我们将会继续深入了解nbt路径,但至于何时更新是个大问题。